Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,4 @@ public record FilterTeamStatusRequest(
taskTitle = taskTitle == null ? "" : taskTitle;
}

// 카테고리 유효성 검사
public boolean isValid() {
// 1차 카테고리가 없으면 2차 카테고리는 선택할 수 없으므로
return mainCategoryIds.isEmpty() || !categoryIds.isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import clap.server.adapter.outbound.persistense.entity.task.constant.LabelColor;
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
import clap.server.domain.model.task.Label;

import java.time.LocalDateTime;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,23 @@
import java.util.List;

public record TeamStatusResponse(
List<TeamTaskResponse> members
List<TeamTaskResponse> members,
int totalInProgressTaskCount,
int totalPendingTaskCount,
int totalTaskCount
) {
// 기존 생성자 (3개 파라미터)
public TeamStatusResponse(List<TeamTaskResponse> members, int totalInProgressTaskCount, int totalPendingTaskCount) {
this(
(members == null) ? List.of() : members,
totalInProgressTaskCount,
totalPendingTaskCount,
totalInProgressTaskCount + totalPendingTaskCount
);
}

// 추가된 생성자 (List만 받음)
public TeamStatusResponse(List<TeamTaskResponse> members) {
this.members = (members == null) ? List.of() : members;
this(members, 0, 0); // 기본값을 사용하여 생성
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package clap.server.adapter.inbound.web.dto.task.response;

import clap.server.adapter.outbound.persistense.entity.task.constant.LabelColor;
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;

import java.time.LocalDateTime;
Expand All @@ -10,11 +11,18 @@ public record TeamTaskItemResponse(
String title,
String mainCategoryName,
String categoryName,
LabelInfo labelInfo,
String requesterNickname,
String requesterImageUrl,
String requesterDepartment,
long processorOrder,
TaskStatus taskStatus,
LocalDateTime createdAt
) {
}
public static record LabelInfo(
String labelName,
LabelColor labelColor
) {
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package clap.server.adapter.inbound.web.dto.task.response;

import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
import com.querydsl.core.annotations.QueryProjection;

import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@
import clap.server.adapter.inbound.web.dto.task.response.TeamStatusResponse;
import clap.server.application.service.task.TeamStatusService;
import clap.server.common.annotation.architecture.WebAdapter;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@Tag(name = "02. Task [담당자]")
@WebAdapter
@RestController
@RequestMapping("/api/team-status")
@RequiredArgsConstructor
@Tag(name = "팀 현황 조회 API")
@WebAdapter
public class TeamStatusController {

@RequestMapping("/api/team-status")
public class TeamStatusController {

private final TeamStatusService teamStatusService;

@Operation(summary = "팀 현황 필터링 조회 API")
@GetMapping("/filter")
public ResponseEntity<TeamStatusResponse> filterTeamStatus(@Valid@ModelAttribute FilterTeamStatusRequest filter) {
public ResponseEntity<TeamStatusResponse> filterTeamStatus(@Validated @ModelAttribute FilterTeamStatusRequest filter) {
TeamStatusResponse response = teamStatusService.filterTeamStatus(filter);
return ResponseEntity.ok(response);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import clap.server.adapter.inbound.web.dto.task.request.FilterTaskBoardRequest;
import clap.server.adapter.inbound.web.dto.task.request.FilterTaskListRequest;
import clap.server.adapter.inbound.web.dto.task.request.FilterTeamStatusRequest;
import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse;
import clap.server.adapter.inbound.web.dto.task.response.TeamTaskItemResponse;
import clap.server.adapter.inbound.web.dto.task.response.TeamTaskItemResponse;
import clap.server.adapter.inbound.web.dto.task.response.TeamTaskResponse;
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
Expand Down Expand Up @@ -56,30 +58,37 @@ public Page<TaskEntity> findTasksAssignedByManager(Long processorId, Pageable pa

@Override
public List<TeamTaskResponse> findTeamStatus(Long memberId, FilterTeamStatusRequest filter) {
// filter가 null인 경우에도 기본적으로 모든 데이터를 조회하도록 처리
BooleanBuilder builder = new BooleanBuilder();

// 담당자 ID 필터링
if (memberId != null) {
builder.and(taskEntity.processor.memberId.eq(memberId));
}
// 필터가 null인 경우, 기본적으로 모든 데이터 조회
if (filter != null) {
// 진행 중 또는 완료 대기 상태 필터링
builder.and(taskEntity.taskStatus.in(TaskStatus.IN_PROGRESS, TaskStatus.PENDING_COMPLETED));

// 작업 타이틀 필터링
if (filter.taskTitle() != null && !filter.taskTitle().isEmpty()) {
builder.and(taskEntity.title.containsIgnoreCase(filter.taskTitle()));
}
// 담당자 ID 필터링
if (memberId != null) {
builder.and(taskEntity.processor.memberId.eq(memberId));
}

// 1차 카테고리 필터링
if (!filter.mainCategoryIds().isEmpty()) {
builder.and(taskEntity.category.mainCategory.categoryId.in(filter.mainCategoryIds()));
}
// 작업 타이틀 필터링
if (filter.taskTitle() != null && !filter.taskTitle().isEmpty()) {
builder.and(taskEntity.title.containsIgnoreCase(filter.taskTitle()));
}

// 2차 카테고리 필터링
if (!filter.categoryIds().isEmpty()) {
builder.and(taskEntity.category.categoryId.in(filter.categoryIds()));
// 1차 카테고리 필터링 (빈 배열인 경우, 필터링하지 않음)
if (filter.mainCategoryIds() != null && !filter.mainCategoryIds().isEmpty()) {
builder.and(taskEntity.category.mainCategory.categoryId.in(filter.mainCategoryIds()));
}

// 2차 카테고리 필터링 (빈 배열인 경우, 필터링하지 않음)
if (filter.categoryIds() != null && !filter.categoryIds().isEmpty()) {
builder.and(taskEntity.category.categoryId.in(filter.categoryIds()));
}
}

// 정렬 조건 적용
OrderSpecifier<?> orderBy = "기여도순".equals(filter.sortBy())
OrderSpecifier<?> orderBy = "기여도순".equals(filter != null ? filter.sortBy() : "")
? new CaseBuilder()
.when(taskEntity.taskStatus.eq(TaskStatus.IN_PROGRESS)
.or(taskEntity.taskStatus.eq(TaskStatus.PENDING_COMPLETED)))
Expand All @@ -106,6 +115,11 @@ public List<TeamTaskResponse> findTeamStatus(Long memberId, FilterTeamStatusRequ
taskEntity.getTitle(),
taskEntity.getCategory().getMainCategory().getName(),
taskEntity.getCategory().getName(),
taskEntity.getLabel() != null ?
new TeamTaskItemResponse.LabelInfo(
taskEntity.getLabel().getLabelName(),
taskEntity.getLabel().getLabelColor()
) : null,
taskEntity.getRequester().getNickname(),
taskEntity.getRequester().getImageUrl(),
taskEntity.getRequester().getDepartment().getName(),
Expand All @@ -114,6 +128,10 @@ public List<TeamTaskResponse> findTeamStatus(Long memberId, FilterTeamStatusRequ
taskEntity.getCreatedAt()
)).collect(Collectors.toList());

int inProgressTaskCount = (int) entry.getValue().stream().filter(t -> t.getTaskStatus() == TaskStatus.IN_PROGRESS).count();
int pendingTaskCount = (int) entry.getValue().stream().filter(t -> t.getTaskStatus() == TaskStatus.PENDING_COMPLETED).count();
int totalTaskCount = inProgressTaskCount + pendingTaskCount;

return new TeamTaskResponse(
entry.getKey(),
entry.getValue().get(0).getProcessor().getNickname(),
Expand All @@ -125,8 +143,11 @@ public List<TeamTaskResponse> findTeamStatus(Long memberId, FilterTeamStatusRequ
taskResponses
);
}).collect(Collectors.toList());

}



private boolean isValidTitle(FilterTeamStatusRequest filter) {
return filter.taskTitle() != null && !filter.taskTitle().isEmpty();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import clap.server.adapter.outbound.persistense.entity.task.TaskEntity;
import clap.server.adapter.outbound.persistense.entity.task.constant.TaskStatus;
import io.lettuce.core.dynamic.annotation.Param;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
Expand Down Expand Up @@ -54,7 +53,7 @@ Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndProcessorOrderAf
Long processorId, TaskStatus taskStatus, Long processorOrder);

@Query("SELECT t FROM TaskEntity t JOIN FETCH t.processor p WHERE (:memberId IS NULL OR p.memberId = :memberId) ")
Page<TeamTaskResponse> findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter, Pageable pageable);
List<TeamTaskResponse> findTeamStatus(@Param("memberId") Long memberId, FilterTeamStatusRequest filter);

Optional<TaskEntity> findTopByProcessor_MemberIdAndTaskStatusAndTaskIdLessThanOrderByTaskIdDesc(Long processorId, TaskStatus taskStatus, Long taskId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
import org.springframework.data.domain.Pageable;

public interface LoadTeamStatusUsecase {
TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter, Pageable pageable);
TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter);
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import clap.server.application.port.inbound.task.FilterTeamStatusUsecase;
import clap.server.application.port.inbound.task.LoadTeamStatusUsecase;
import clap.server.application.port.outbound.task.LoadTaskPort;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;
Expand All @@ -21,8 +20,8 @@ public TeamStatusService(LoadTaskPort loadTaskPort) {
}

@Override
public TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter, Pageable pageable) {
List<TeamTaskResponse> members = loadTaskPort.findTeamStatus(memberId, filter); // 페이징 처리
public TeamStatusResponse getTeamStatus(Long memberId, FilterTeamStatusRequest filter) {
List<TeamTaskResponse> members = loadTaskPort.findTeamStatus(memberId, filter);
return new TeamStatusResponse(members);
}

Expand Down