diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/entity/Deposit.java b/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/entity/Deposit.java index 139e385..a0431e6 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/entity/Deposit.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/Deposit/entity/Deposit.java @@ -2,13 +2,11 @@ import backend.pirocheck.User.entity.User; import jakarta.persistence.*; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; @Entity @Getter +@Setter @NoArgsConstructor @AllArgsConstructor @Builder @@ -37,4 +35,12 @@ public void updateAmounts(int descentAssignment, int descentAttendance, int asce this.amount = Math.min(calculateAmount, 120000); // 12만원 넘어가지 않도록 } + // 방어권 업데이트 + public void updateDefence(int newAscentDefence) { + this.ascentDefence = newAscentDefence; + int calculateAmount = 120000 - this.descentAssignment - this.descentAttendance + newAscentDefence; + this.amount = Math.min(calculateAmount, 120000); + + } + } diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/Controller/ManageStudentsController.java b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/Controller/ManageStudentsController.java new file mode 100644 index 0000000..043b571 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/Controller/ManageStudentsController.java @@ -0,0 +1,37 @@ +package backend.pirocheck.ManageStudents.Controller; + +import backend.pirocheck.ManageStudents.dto.request.DefenceUpdateReqDto; +import backend.pirocheck.ManageStudents.dto.response.ManageStudentDetailResDto; +import backend.pirocheck.ManageStudents.dto.response.ManageStudentsListResDto; +import backend.pirocheck.ManageStudents.service.ManageStudentsService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/api/admin/managestudent") +@RequiredArgsConstructor +public class ManageStudentsController { + + private final ManageStudentsService manageStudentsService; + + // 수강생 리스트 조회 + @GetMapping("") + public List getStudents(@RequestParam(required = false) String name) { + return manageStudentsService.searchMembers(name); + } + + // 수강생 상세 조회 + @GetMapping("/{studentId}") + public ManageStudentDetailResDto getStudentDetail(@PathVariable Long studentId) { + return manageStudentsService.getMemberDetail(studentId); + } + + // 방어권 업데이트 + @PatchMapping("/{studentId}/defence") + public void updateDefence(@PathVariable Long studentId, @RequestBody DefenceUpdateReqDto req) { + manageStudentsService.updateDefence(studentId, req.getDefence()); + } + +} diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/request/DefenceUpdateReqDto.java b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/request/DefenceUpdateReqDto.java new file mode 100644 index 0000000..78e39f7 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/request/DefenceUpdateReqDto.java @@ -0,0 +1,11 @@ +package backend.pirocheck.ManageStudents.dto.request; + + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class DefenceUpdateReqDto { + private int defence; +} diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/response/ManageStudentDetailResDto.java b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/response/ManageStudentDetailResDto.java new file mode 100644 index 0000000..e5206fc --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/response/ManageStudentDetailResDto.java @@ -0,0 +1,16 @@ +package backend.pirocheck.ManageStudents.dto.response; + +import lombok.Builder; +import lombok.Getter; + +import java.util.List; + +@Getter +@Builder +public class ManageStudentDetailResDto { + + private String name; + private int deposit; + private int defence; // 방어권 + private List assignmentTitles; // 과제 제목 리스트 +} diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/response/ManageStudentsListResDto.java b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/response/ManageStudentsListResDto.java new file mode 100644 index 0000000..d5e028f --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/dto/response/ManageStudentsListResDto.java @@ -0,0 +1,13 @@ +package backend.pirocheck.ManageStudents.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ManageStudentsListResDto { + + private Long id; + private String name; + +} diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/service/ManageStudentsService.java b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/service/ManageStudentsService.java new file mode 100644 index 0000000..e28c409 --- /dev/null +++ b/backend/pirocheck/src/main/java/backend/pirocheck/ManageStudents/service/ManageStudentsService.java @@ -0,0 +1,86 @@ +package backend.pirocheck.ManageStudents.service; + +import backend.pirocheck.Deposit.entity.Deposit; +import backend.pirocheck.Deposit.repository.DepositRepository; +import backend.pirocheck.ManageStudents.dto.response.ManageStudentDetailResDto; +import backend.pirocheck.ManageStudents.dto.response.ManageStudentsListResDto; +import backend.pirocheck.User.entity.Role; +import backend.pirocheck.User.entity.User; +import backend.pirocheck.User.repository.UserRepository; +import backend.pirocheck.assignment.entity.Assignment; +import backend.pirocheck.assignment.repository.AssignmentRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ManageStudentsService { + + private final UserRepository userRepository; + private final DepositRepository depositRepository; + private final AssignmentRepository assignmentRepository; + + // 수강생 조회 + public List searchMembers(String name) { + List users; + + if(name == null || name.isBlank()) { + // 검색어가 없으면 맴버 전체 조회 + users = userRepository.findByRole(Role.MEMBER); + } + else { + // 이름 검색 + users = userRepository.findByNameContainingAndRole(name, Role.MEMBER); + } + + return users.stream() + .map(user -> new ManageStudentsListResDto(user.getId(), user.getName())) + .collect(Collectors.toList()); + } + + // 수강생 상세 조회 + public ManageStudentDetailResDto getMemberDetail(Long studentId) { + // User 조회 + User user = userRepository.findById(studentId) + .orElseThrow(() -> new RuntimeException("해당 맴버가 존재하지 않습니다.")); + + // deposit 조회 + Deposit deposit = depositRepository.findByUser(user); + if (deposit == null) { + throw new RuntimeException("해당 수강생의 보증금 정보가 없습니다."); + } + + // Assignment 리스트 조회 + List assignments = assignmentRepository.findByUserId(studentId); + + // 과제 제목만 리스트로 변환 + List assignmentTitles = assignments.stream() + .map(Assignment::getAssignmentName) + .toList(); + + // ManageStudentDetailResDto 조립 + return ManageStudentDetailResDto.builder() + .name(user.getName()) + .deposit(deposit.getAmount()) + .defence(deposit.getAscentDefence()) + .assignmentTitles(assignmentTitles) + .build(); + } + + // 방어권 업데이트 + public void updateDefence(Long studentId, int defence) { + User user = userRepository.findById(studentId) + .orElseThrow(() -> new RuntimeException("해당 수강생의 보증금 정보가 없습니다.")); + Deposit deposit = depositRepository.findByUser(user); + + // 업데이트 + deposit.updateDefence(defence); + + // 저장 + depositRepository.save(deposit); + + } +} diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java b/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java index 4fd3755..f26232f 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/User/exception/GlobalExceptionHandler.java @@ -16,4 +16,12 @@ public ResponseEntity> handleInvalidLoginException(InvalidLoginEx .status(HttpStatus.UNAUTHORIZED) // 401 상태 코드 .body(ApiResponse.error(e.getMessage())); // 에러 메시지 전달 } + + // RuntimeException (유저관리 상세페이지) + @ExceptionHandler(RuntimeException.class) + public ResponseEntity> handleRuntimeException(RuntimeException ex) { + return ResponseEntity + .status(HttpStatus.BAD_REQUEST) // 404 + .body(ApiResponse.error(ex.getMessage())); + } } diff --git a/backend/pirocheck/src/main/java/backend/pirocheck/User/repository/UserRepository.java b/backend/pirocheck/src/main/java/backend/pirocheck/User/repository/UserRepository.java index 9f80d25..8859494 100644 --- a/backend/pirocheck/src/main/java/backend/pirocheck/User/repository/UserRepository.java +++ b/backend/pirocheck/src/main/java/backend/pirocheck/User/repository/UserRepository.java @@ -12,4 +12,7 @@ public interface UserRepository extends JpaRepository { Optional findByName(String name); List findByRole(Role role); + + // 학생 이름으로 검색기능 + List findByNameContainingAndRole(String name, Role role); } diff --git a/frontend/public/assets/img/managestudent.svg b/frontend/public/assets/img/managestudent.svg new file mode 100644 index 0000000..bad007f --- /dev/null +++ b/frontend/public/assets/img/managestudent.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index b11b9d0..9f4508b 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -15,6 +15,7 @@ function App() { return ( + } /> } /> } /> } /> @@ -24,7 +25,6 @@ function App() { } /> } /> } /> - } /> ); diff --git a/frontend/src/components/Header.jsx b/frontend/src/components/Header.jsx index a4f62b1..5c3501d 100644 --- a/frontend/src/components/Header.jsx +++ b/frontend/src/components/Header.jsx @@ -10,8 +10,12 @@ const Header = () => { if (path.includes("assignment")) title = "ASSIGNMENT\nCHECK"; else if (path.includes("deposit")) title = "DEPOSIT"; else if (path.includes("attendance")) title = "ATTENDANCE\nCHECK"; + else if (path.includes("magagestudent")) title = "수강생관리"; + else if (path.includes("magagetask")) title = "과제 관리"; + else if (path.includes("attendancecode")) title = "출석코드 생성"; - const showRightButton = !path.includes("deposit"); + const showRightDeposit = !path.includes("deposit"); + const showRightMagageStudent = path.includes("attendancecode"); return (
@@ -28,7 +32,7 @@ const Header = () => { />

{title}

- {showRightButton ? ( + {showRightDeposit ? ( + ) : null}
); }; diff --git a/frontend/src/pages/admin/AttendanceCode.jsx b/frontend/src/pages/admin/AttendanceCode.jsx index d184e1d..6e18188 100644 --- a/frontend/src/pages/admin/AttendanceCode.jsx +++ b/frontend/src/pages/admin/AttendanceCode.jsx @@ -1,4 +1,17 @@ +import Header from "../../components/Header"; +import style from "./AttendanceCode.module.css"; const AttendanceCode = () => { - return

출석코드 생성

; + return ( +
+
+
+
+
+
+
+
+ +
+ ); }; export default AttendanceCode; diff --git a/frontend/src/pages/admin/AttendanceCode.module.css b/frontend/src/pages/admin/AttendanceCode.module.css new file mode 100644 index 0000000..e92a220 --- /dev/null +++ b/frontend/src/pages/admin/AttendanceCode.module.css @@ -0,0 +1,28 @@ +.num_wrapper { + width: 73px; + height: 101px; + background-color: #575757; + border-radius: 21px; + border: 1px solid #a6a6a6; +} +.num_container { + margin-top: 130px; + display: flex; + flex-direction: row; + gap: 8px; +} +.attendancecode_wraper { + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; +} +.createbutton { + width: 60px; + height: 42px; + background-color: #575757; + border-radius: 21px; + margin-top: 60px; + border: 1px solid #a6a6a6; + color: white; +}