mirror of
https://github.com/hwanny1128/HGZero.git
synced 2026-01-21 12:36:25 +00:00
Chore: 회의록 목록 조회 API 실제 데이터 연동
This commit is contained in:
parent
e5337385f4
commit
45dc77cddf
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -116,6 +116,11 @@ public class MinutesDTO {
|
||||
*/
|
||||
private final Integer completedTodoCount;
|
||||
|
||||
/**
|
||||
* 참석자 수
|
||||
*/
|
||||
private final Integer participantCount;
|
||||
|
||||
/**
|
||||
* 회의 정보
|
||||
*/
|
||||
|
||||
@ -44,6 +44,7 @@ public class MinutesService implements
|
||||
private final MinutesSectionReader minutesSectionReader;
|
||||
private final MinutesSectionWriter minutesSectionWriter;
|
||||
private final CacheService cacheService;
|
||||
private final com.unicorn.hgzero.meeting.biz.usecase.out.ParticipantReader participantReader;
|
||||
|
||||
/**
|
||||
* 회의록 생성
|
||||
@ -317,6 +318,29 @@ public class MinutesService implements
|
||||
* Minutes 도메인을 MinutesDTO로 변환
|
||||
*/
|
||||
private MinutesDTO convertToMinutesDTO(Minutes minutes) {
|
||||
// 회의 정보 조회
|
||||
String meetingTitle = "회의 제목 없음";
|
||||
try {
|
||||
Meeting meeting = meetingReader.findById(minutes.getMeetingId()).orElse(null);
|
||||
if (meeting != null) {
|
||||
meetingTitle = meeting.getTitle();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("회의 정보 조회 실패 - meetingId: {}", minutes.getMeetingId(), e);
|
||||
}
|
||||
|
||||
// TODO 정보는 추후 구현 (현재는 기본값)
|
||||
int todoCount = 0;
|
||||
int completedTodoCount = 0;
|
||||
|
||||
// 참석자 수 계산 (모든 참석자)
|
||||
int participantCount = 0;
|
||||
try {
|
||||
participantCount = participantReader.countParticipantsByMeetingId(minutes.getMeetingId());
|
||||
} catch (Exception e) {
|
||||
log.warn("참석자 수 계산 실패 - meetingId: {}", minutes.getMeetingId(), e);
|
||||
}
|
||||
|
||||
return MinutesDTO.builder()
|
||||
.minutesId(minutes.getMinutesId())
|
||||
.meetingId(minutes.getMeetingId())
|
||||
@ -327,11 +351,11 @@ public class MinutesService implements
|
||||
.lastModifiedAt(minutes.getLastModifiedAt())
|
||||
.createdBy(minutes.getCreatedBy())
|
||||
.lastModifiedBy(minutes.getLastModifiedBy())
|
||||
// 추가 필드들은 임시로 기본값 설정
|
||||
.meetingTitle("임시 회의 제목")
|
||||
.todoCount(0)
|
||||
.completedTodoCount(0)
|
||||
.memo("")
|
||||
.meetingTitle(meetingTitle)
|
||||
.todoCount(todoCount)
|
||||
.completedTodoCount(completedTodoCount)
|
||||
.participantCount(participantCount)
|
||||
.memo("") // 메모 필드는 추후 구현
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,4 +21,9 @@ public interface ParticipantReader {
|
||||
* 특정 회의에 특정 사용자가 참석자로 등록되어 있는지 확인
|
||||
*/
|
||||
boolean existsParticipant(String meetingId, String userId);
|
||||
|
||||
/**
|
||||
* 회의 ID로 참석자 수 조회 (모든 참석자)
|
||||
*/
|
||||
int countParticipantsByMeetingId(String meetingId);
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package com.unicorn.hgzero.meeting.infra.controller;
|
||||
|
||||
import com.unicorn.hgzero.common.dto.ApiResponse;
|
||||
import com.unicorn.hgzero.common.exception.BusinessException;
|
||||
import com.unicorn.hgzero.meeting.biz.domain.Minutes;
|
||||
import com.unicorn.hgzero.meeting.biz.dto.MinutesDTO;
|
||||
import com.unicorn.hgzero.meeting.biz.service.MinutesService;
|
||||
import com.unicorn.hgzero.meeting.biz.service.MinutesSectionService;
|
||||
@ -16,6 +17,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@ -69,40 +71,37 @@ public class MinutesController {
|
||||
userId, page, size, status, participationType, search);
|
||||
|
||||
try {
|
||||
// Mock 데이터 생성 (프론트엔드 테스트용)
|
||||
List<MinutesListResponse.MinutesItem> mockMinutes = createMockMinutesList(userId);
|
||||
// 정렬 및 페이징 설정
|
||||
Sort sort = createSort(sortBy, sortDir);
|
||||
Pageable pageable = PageRequest.of(page, size, sort);
|
||||
|
||||
// 필터링 적용
|
||||
List<MinutesListResponse.MinutesItem> filteredMinutes = mockMinutes.stream()
|
||||
// 실제 데이터 조회
|
||||
Page<MinutesDTO> minutesPage = minutesService.getMinutesListByUserId(userId, pageable);
|
||||
|
||||
// DTO를 Response 형식으로 변환
|
||||
List<MinutesListResponse.MinutesItem> minutesList = minutesPage.getContent().stream()
|
||||
.map(this::convertToMinutesItem)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 필터링 적용 (상태별)
|
||||
List<MinutesListResponse.MinutesItem> filteredMinutes = minutesList.stream()
|
||||
.filter(item -> filterByStatus(item, status))
|
||||
.filter(item -> filterByParticipationType(item, participationType, userId))
|
||||
.filter(item -> filterBySearch(item, search))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 정렬 적용
|
||||
applySorting(filteredMinutes, sortBy, sortDir);
|
||||
|
||||
// 페이징 적용
|
||||
int startIndex = page * size;
|
||||
int endIndex = Math.min(startIndex + size, filteredMinutes.size());
|
||||
List<MinutesListResponse.MinutesItem> pagedMinutes =
|
||||
startIndex < filteredMinutes.size() ?
|
||||
filteredMinutes.subList(startIndex, endIndex) :
|
||||
List.of();
|
||||
|
||||
// 통계 계산
|
||||
MinutesListResponse.Statistics stats = calculateStatistics(mockMinutes, participationType, userId);
|
||||
// 통계 계산 (전체 데이터 기준)
|
||||
MinutesListResponse.Statistics stats = calculateRealStatistics(userId, participationType);
|
||||
|
||||
MinutesListResponse response = MinutesListResponse.builder()
|
||||
.minutesList(pagedMinutes)
|
||||
.totalCount(filteredMinutes.size())
|
||||
.minutesList(filteredMinutes)
|
||||
.totalCount((int) minutesPage.getTotalElements())
|
||||
.currentPage(page)
|
||||
.totalPages((int) Math.ceil((double) filteredMinutes.size() / size))
|
||||
.totalPages(minutesPage.getTotalPages())
|
||||
.statistics(stats)
|
||||
.build();
|
||||
|
||||
log.info("회의록 목록 조회 성공 - userId: {}, total: {}, filtered: {}, paged: {}",
|
||||
userId, mockMinutes.size(), filteredMinutes.size(), pagedMinutes.size());
|
||||
log.info("회의록 목록 조회 성공 - userId: {}, total: {}, filtered: {}",
|
||||
userId, minutesPage.getTotalElements(), filteredMinutes.size());
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
|
||||
} catch (Exception e) {
|
||||
@ -126,13 +125,14 @@ public class MinutesController {
|
||||
log.info("회의록 상세 조회 요청 - userId: {}, minutesId: {}", userId, minutesId);
|
||||
|
||||
try {
|
||||
// Mock 데이터 생성 (프론트엔드 테스트용)
|
||||
MinutesDetailResponse response = createMockMinutesDetail(minutesId, userId);
|
||||
// 실제 데이터 조회
|
||||
MinutesDTO minutesDTO = minutesService.getMinutesById(minutesId);
|
||||
MinutesDetailResponse response = convertToMinutesDetailResponse(minutesDTO);
|
||||
|
||||
// 캐시 저장
|
||||
cacheService.cacheMinutesDetail(minutesId, response);
|
||||
|
||||
log.info("회의록 상세 조회 성공 (Mock) - minutesId: {}", minutesId);
|
||||
log.info("회의록 상세 조회 성공 - minutesId: {}", minutesId);
|
||||
return ResponseEntity.ok(ApiResponse.success(response));
|
||||
|
||||
} catch (Exception e) {
|
||||
@ -326,7 +326,60 @@ public class MinutesController {
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
/**
|
||||
* 정렬 옵션 생성
|
||||
*/
|
||||
private Sort createSort(String sortBy, String sortDir) {
|
||||
Sort.Direction direction = "asc".equalsIgnoreCase(sortDir) ? Sort.Direction.ASC : Sort.Direction.DESC;
|
||||
|
||||
switch (sortBy) {
|
||||
case "title":
|
||||
return Sort.by(direction, "title");
|
||||
case "meeting":
|
||||
return Sort.by(direction, "createdAt"); // 회의 일시로 정렬 (임시로 생성일시 사용)
|
||||
case "modified":
|
||||
default:
|
||||
return Sort.by(direction, "lastModifiedAt");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 실제 통계 계산
|
||||
*/
|
||||
private MinutesListResponse.Statistics calculateRealStatistics(String userId, String participationType) {
|
||||
try {
|
||||
// 전체 회의록 조회 (작성자 기준)
|
||||
List<Minutes> allMinutes = minutesService.getMinutesByCreator(userId);
|
||||
|
||||
long totalCount = allMinutes.size();
|
||||
long draftCount = allMinutes.stream()
|
||||
.filter(m -> "DRAFT".equals(m.getStatus()))
|
||||
.count();
|
||||
long completeCount = allMinutes.stream()
|
||||
.filter(m -> "FINALIZED".equals(m.getStatus()))
|
||||
.count();
|
||||
|
||||
return MinutesListResponse.Statistics.builder()
|
||||
.totalCount(totalCount)
|
||||
.draftCount(draftCount)
|
||||
.completeCount(completeCount)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
log.warn("통계 계산 실패, 기본값 반환 - userId: {}", userId, e);
|
||||
return MinutesListResponse.Statistics.builder()
|
||||
.totalCount(0L)
|
||||
.draftCount(0L)
|
||||
.completeCount(0L)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private MinutesListResponse.MinutesItem convertToMinutesItem(MinutesDTO minutesDTO) {
|
||||
// 완료율 계산
|
||||
int completionRate = minutesDTO.getTodoCount() > 0 ?
|
||||
(minutesDTO.getCompletedTodoCount() * 100) / minutesDTO.getTodoCount() : 100;
|
||||
|
||||
return MinutesListResponse.MinutesItem.builder()
|
||||
.minutesId(minutesDTO.getMinutesId())
|
||||
.title(minutesDTO.getTitle())
|
||||
@ -335,10 +388,14 @@ public class MinutesController {
|
||||
.version(minutesDTO.getVersion())
|
||||
.createdAt(minutesDTO.getCreatedAt())
|
||||
.lastModifiedAt(minutesDTO.getLastModifiedAt())
|
||||
.meetingDate(minutesDTO.getCreatedAt()) // 임시로 생성일시 사용
|
||||
.createdBy(minutesDTO.getCreatedBy())
|
||||
.lastModifiedBy(minutesDTO.getLastModifiedBy())
|
||||
.participantCount(minutesDTO.getParticipantCount() != null ? minutesDTO.getParticipantCount() : 0)
|
||||
.todoCount(minutesDTO.getTodoCount())
|
||||
.completedTodoCount(minutesDTO.getCompletedTodoCount())
|
||||
.completionRate(completionRate)
|
||||
.isCreatedByUser(true) // 현재는 작성자 기준으로만 조회하므로 true
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -497,18 +554,10 @@ public class MinutesController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 참여 유형별 필터링
|
||||
* 참여 유형별 필터링 - 현재는 사용하지 않음 (작성자 기준으로만 조회)
|
||||
*/
|
||||
private boolean filterByParticipationType(MinutesListResponse.MinutesItem item, String participationType, String userId) {
|
||||
if (participationType == null || participationType.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if ("created".equals(participationType)) {
|
||||
return item.isCreatedByUser();
|
||||
}
|
||||
if ("attended".equals(participationType)) {
|
||||
return !item.isCreatedByUser();
|
||||
}
|
||||
// 현재는 작성자 기준으로만 조회하므로 항상 true 반환
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -870,8 +919,59 @@ public class MinutesController {
|
||||
|
||||
|
||||
private MinutesDetailResponse convertToMinutesDetailResponse(MinutesDTO minutesDTO) {
|
||||
// Mock 데이터로 대체 (프로토타입용)
|
||||
return createMockMinutesDetail(minutesDTO.getMinutesId(), "user123");
|
||||
// 기본 회의록 정보는 실제 데이터 사용
|
||||
MinutesDetailResponse.MeetingInfo meetingInfo = MinutesDetailResponse.MeetingInfo.builder()
|
||||
.meetingId(minutesDTO.getMeetingId())
|
||||
.title(minutesDTO.getMeetingTitle())
|
||||
.location("회의실 정보 없음") // 추후 실제 데이터로 변경 필요
|
||||
.participants(List.of()) // 추후 실제 참석자 정보로 변경 필요
|
||||
.build();
|
||||
|
||||
MinutesDetailResponse.Statistics stats = MinutesDetailResponse.Statistics.builder()
|
||||
.participantCount(minutesDTO.getParticipantCount() != null ? minutesDTO.getParticipantCount() : 0)
|
||||
.durationMinutes(90) // 기본값 - 추후 실제 데이터로 변경 필요
|
||||
.agendaCount(0) // 기본값 - 추후 실제 데이터로 변경 필요
|
||||
.todoCount(minutesDTO.getTodoCount() != null ? minutesDTO.getTodoCount() : 0)
|
||||
.build();
|
||||
|
||||
MinutesDetailResponse.DashboardInfo dashboardInfo = MinutesDetailResponse.DashboardInfo.builder()
|
||||
.keyPoints(List.of()) // 추후 실제 데이터로 변경 필요
|
||||
.keywords(List.of()) // 추후 실제 데이터로 변경 필요
|
||||
.stats(stats)
|
||||
.decisions(List.of()) // 추후 실제 데이터로 변경 필요
|
||||
.todoProgress(MinutesDetailResponse.TodoProgress.builder()
|
||||
.totalCount(minutesDTO.getTodoCount() != null ? minutesDTO.getTodoCount() : 0)
|
||||
.completedCount(minutesDTO.getCompletedTodoCount() != null ? minutesDTO.getCompletedTodoCount() : 0)
|
||||
.progressPercentage(calculateProgressPercentage(minutesDTO.getTodoCount(), minutesDTO.getCompletedTodoCount()))
|
||||
.todos(List.of()) // 추후 실제 데이터로 변경 필요
|
||||
.build())
|
||||
.relatedMinutes(List.of()) // 추후 실제 데이터로 변경 필요
|
||||
.build();
|
||||
|
||||
return MinutesDetailResponse.builder()
|
||||
.minutesId(minutesDTO.getMinutesId())
|
||||
.title(minutesDTO.getTitle())
|
||||
.memo(minutesDTO.getMemo() != null ? minutesDTO.getMemo() : "")
|
||||
.status(minutesDTO.getStatus())
|
||||
.version(minutesDTO.getVersion())
|
||||
.createdAt(minutesDTO.getCreatedAt())
|
||||
.lastModifiedAt(minutesDTO.getLastModifiedAt())
|
||||
.createdBy(minutesDTO.getCreatedBy())
|
||||
.lastModifiedBy(minutesDTO.getLastModifiedBy())
|
||||
.meeting(meetingInfo)
|
||||
.dashboard(dashboardInfo)
|
||||
.agendas(List.of()) // 추후 실제 안건 데이터로 변경 필요
|
||||
.build();
|
||||
}
|
||||
|
||||
private int calculateProgressPercentage(Integer totalCount, Integer completedCount) {
|
||||
if (totalCount == null || totalCount == 0) {
|
||||
return 100;
|
||||
}
|
||||
if (completedCount == null) {
|
||||
return 0;
|
||||
}
|
||||
return (completedCount * 100) / totalCount;
|
||||
}
|
||||
|
||||
}
|
||||
@ -45,6 +45,12 @@ public class ParticipantGateway implements ParticipantReader, ParticipantWriter
|
||||
return participantRepository.existsByMeetingIdAndUserId(meetingId, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public int countParticipantsByMeetingId(String meetingId) {
|
||||
return participantRepository.countByMeetingId(meetingId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void saveParticipant(String meetingId, String userId) {
|
||||
|
||||
@ -42,4 +42,9 @@ public interface MeetingParticipantJpaRepository extends JpaRepository<MeetingPa
|
||||
* 회의 ID와 사용자 ID로 참석자 존재 여부 확인
|
||||
*/
|
||||
boolean existsByMeetingIdAndUserId(String meetingId, String userId);
|
||||
|
||||
/**
|
||||
* 회의 ID로 참석자 수 조회 (모든 참석자)
|
||||
*/
|
||||
int countByMeetingId(String meetingId);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user