feat: enhanced employee edit modal (profile, equipment, dispatch, status)

This commit is contained in:
pray4skylark
2026-06-05 11:00:09 +09:00
parent face097785
commit eb5734aad6
5 changed files with 872 additions and 157 deletions
@@ -10,7 +10,11 @@ import com.srsystem.dto.UpdateAchievementsRequest;
import com.srsystem.entity.DispatchHistory; import com.srsystem.entity.DispatchHistory;
import com.srsystem.entity.Employee; import com.srsystem.entity.Employee;
import com.srsystem.entity.EmployeeEmergencyContact; import com.srsystem.entity.EmployeeEmergencyContact;
import com.srsystem.entity.EquipmentAssignment;
import com.srsystem.entity.enums.DispatchStatus;
import com.srsystem.entity.enums.EmpStatus; import com.srsystem.entity.enums.EmpStatus;
import com.srsystem.entity.enums.RoleCode;
import com.srsystem.repository.EquipmentAssignmentRepository;
import com.srsystem.service.DispatchHistoryService; import com.srsystem.service.DispatchHistoryService;
import com.srsystem.service.EmployeeService; import com.srsystem.service.EmployeeService;
import com.srsystem.service.PortfolioService; import com.srsystem.service.PortfolioService;
@@ -42,6 +46,7 @@ public class EmployeeController {
private final EmployeeService employeeService; private final EmployeeService employeeService;
private final DispatchHistoryService dispatchHistoryService; private final DispatchHistoryService dispatchHistoryService;
private final PortfolioService portfolioService; private final PortfolioService portfolioService;
private final EquipmentAssignmentRepository equipmentAssignmentRepository;
@Operation(summary = "직원 목록 조회", description = "페이징된 직원 목록을 조회합니다. 상태 필터 옵션 포함") @Operation(summary = "직원 목록 조회", description = "페이징된 직원 목록을 조회합니다. 상태 필터 옵션 포함")
@PreAuthorize("hasAnyRole('MANAGER', 'ADMIN')") @PreAuthorize("hasAnyRole('MANAGER', 'ADMIN')")
@@ -86,7 +91,7 @@ public class EmployeeController {
return ResponseEntity.ok(ApiResponse.ok("직원이 등록되었습니다", created)); return ResponseEntity.ok(ApiResponse.ok("직원이 등록되었습니다", created));
} }
@Operation(summary = "직원 정보 수정", description = "직원 정보를 수정합니다 (퇴사자는 수정 불가)") @Operation(summary = "직원 정보 수정", description = "기본 정보(이름/이메일/전화번호/생년월일/학력/전공/졸업일/거주지/프로필사진) 수정")
@PreAuthorize("hasRole('ADMIN')") @PreAuthorize("hasRole('ADMIN')")
@PutMapping("/{empId}") @PutMapping("/{empId}")
public ResponseEntity<ApiResponse<Employee>> update( public ResponseEntity<ApiResponse<Employee>> update(
@@ -96,6 +101,37 @@ public class EmployeeController {
return ResponseEntity.ok(ApiResponse.ok("직원 정보가 수정되었습니다", updated)); return ResponseEntity.ok(ApiResponse.ok("직원 정보가 수정되었습니다", updated));
} }
@Operation(summary = "직원 재직 상태 변경", description = "ACTIVE/ON_LEAVE/RESIGNED + 퇴사일")
@PreAuthorize("hasRole('ADMIN')")
@PutMapping("/{empId}/status")
public ResponseEntity<ApiResponse<Employee>> updateStatus(
@PathVariable Long empId, @RequestBody Map<String, String> body) {
EmpStatus status = EmpStatus.valueOf(body.get("empStatus"));
String leftDate = body.get("leftDate");
Employee updated = employeeService.updateStatus(empId, status, leftDate);
return ResponseEntity.ok(ApiResponse.ok("상태가 변경되었습니다", updated));
}
@Operation(summary = "직원 권한 변경", description = "ADMIN/ MANAGER/ EMPLOYEE")
@PreAuthorize("hasRole('ADMIN')")
@PutMapping("/{empId}/role")
public ResponseEntity<ApiResponse<Employee>> updateRole(
@PathVariable Long empId, @RequestBody Map<String, String> body) {
RoleCode role = RoleCode.valueOf(body.get("roleCode"));
Employee updated = employeeService.updateRole(empId, role);
return ResponseEntity.ok(ApiResponse.ok("권한이 변경되었습니다", updated));
}
@Operation(summary = "직원 파견 상태 변경", description = "WAITING/ DISPATCHED")
@PreAuthorize("hasAnyRole('MANAGER', 'ADMIN')")
@PutMapping("/{empId}/dispatch-status")
public ResponseEntity<ApiResponse<Employee>> updateDispatchStatus(
@PathVariable Long empId, @RequestBody Map<String, String> body) {
DispatchStatus status = DispatchStatus.valueOf(body.get("dispatchStatus"));
Employee updated = employeeService.updateDispatchStatus(empId, status);
return ResponseEntity.ok(ApiResponse.ok("파견 상태가 변경되었습니다", updated));
}
@Operation(summary = "직원 삭제", description = "직원을 삭제합니다 (Soft Delete, 퇴사자는 삭제 불가)") @Operation(summary = "직원 삭제", description = "직원을 삭제합니다 (Soft Delete, 퇴사자는 삭제 불가)")
@PreAuthorize("hasRole('ADMIN')") @PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/{empId}") @DeleteMapping("/{empId}")
@@ -154,8 +190,16 @@ public class EmployeeController {
return ResponseEntity.ok(ApiResponse.ok("성과가 저장되었습니다", null)); return ResponseEntity.ok(ApiResponse.ok("성과가 저장되었습니다", null));
} }
// ---- Emergency Contacts ---- @Operation(summary = "직원 지급 장비 조회", description = "직원에게 지급된 장비 목록을 조회합니다 (반납되지 않은)")
@PreAuthorize("hasAnyRole('EMPLOYEE', 'MANAGER', 'ADMIN')")
@Transactional(readOnly = true)
@GetMapping("/{empId}/equipment")
public ResponseEntity<ApiResponse<List<EquipmentAssignment>>> getEquipment(@PathVariable Long empId) {
List<EquipmentAssignment> assignments = equipmentAssignmentRepository.findByUser_EmpIdAndReturnedDateIsNull(empId);
return ResponseEntity.ok(ApiResponse.ok(assignments));
}
// ---- Emergency Contacts ----
@Operation(summary = "비상연락망 목록 조회", description = "직원의 비상연락망 목록을 조회합니다") @Operation(summary = "비상연락망 목록 조회", description = "직원의 비상연락망 목록을 조회합니다")
@PreAuthorize("hasAnyRole('EMPLOYEE', 'MANAGER', 'ADMIN')") @PreAuthorize("hasAnyRole('EMPLOYEE', 'MANAGER', 'ADMIN')")
@GetMapping("/{empId}/emergency-contacts") @GetMapping("/{empId}/emergency-contacts")
@@ -11,4 +11,6 @@ import java.util.Optional;
public interface EquipmentAssignmentRepository extends JpaRepository<EquipmentAssignment, Long> { public interface EquipmentAssignmentRepository extends JpaRepository<EquipmentAssignment, Long> {
List<EquipmentAssignment> findByEquipment_EquipmentId(Long equipmentId); List<EquipmentAssignment> findByEquipment_EquipmentId(Long equipmentId);
Optional<EquipmentAssignment> findByEquipment_EquipmentIdAndReturnedDateIsNull(Long equipmentId); Optional<EquipmentAssignment> findByEquipment_EquipmentIdAndReturnedDateIsNull(Long equipmentId);
List<EquipmentAssignment> findByUser_EmpIdAndReturnedDateIsNull(Long empId);
List<EquipmentAssignment> findByUser_EmpIdOrderByAssignedDateDesc(Long empId);
} }
@@ -5,7 +5,9 @@ import com.srsystem.dto.EmployeeSearchResult;
import com.srsystem.dto.EmployeeSummary; import com.srsystem.dto.EmployeeSummary;
import com.srsystem.entity.Employee; import com.srsystem.entity.Employee;
import com.srsystem.entity.EmployeeEmergencyContact; import com.srsystem.entity.EmployeeEmergencyContact;
import com.srsystem.entity.enums.DispatchStatus;
import com.srsystem.entity.enums.EmpStatus; import com.srsystem.entity.enums.EmpStatus;
import com.srsystem.entity.enums.RoleCode;
import com.srsystem.exception.BusinessException; import com.srsystem.exception.BusinessException;
import com.srsystem.exception.ErrorCode; import com.srsystem.exception.ErrorCode;
import com.srsystem.repository.DispatchHistoryRepository; import com.srsystem.repository.DispatchHistoryRepository;
@@ -18,6 +20,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -99,11 +102,7 @@ public class EmployeeService {
employee.setName(updateRequest.getName()); employee.setName(updateRequest.getName());
employee.setEmail(updateRequest.getEmail()); employee.setEmail(updateRequest.getEmail());
employee.setPhone(updateRequest.getPhone()); employee.setPhone(updateRequest.getPhone());
employee.setRoleCode(updateRequest.getRoleCode());
employee.setEmpStatus(updateRequest.getEmpStatus());
employee.setDispatchStatus(updateRequest.getDispatchStatus());
employee.setJoinedDate(updateRequest.getJoinedDate()); employee.setJoinedDate(updateRequest.getJoinedDate());
employee.setLeftDate(updateRequest.getLeftDate());
employee.setBirthDate(updateRequest.getBirthDate()); employee.setBirthDate(updateRequest.getBirthDate());
employee.setEducation(updateRequest.getEducation()); employee.setEducation(updateRequest.getEducation());
employee.setMajor(updateRequest.getMajor()); employee.setMajor(updateRequest.getMajor());
@@ -111,13 +110,36 @@ public class EmployeeService {
employee.setResidence(updateRequest.getResidence()); employee.setResidence(updateRequest.getResidence());
employee.setProfileImage(updateRequest.getProfileImage()); employee.setProfileImage(updateRequest.getProfileImage());
if (updateRequest.getPassword() != null && !updateRequest.getPassword().isBlank()) {
employee.setPassword(passwordEncoder.encode(updateRequest.getPassword()));
}
return employee; return employee;
} }
@Transactional
public Employee updateStatus(Long empId, EmpStatus status, String leftDate) {
Employee employee = findById(empId);
employee.setEmpStatus(status);
if (leftDate != null && !leftDate.isBlank()) {
employee.setLeftDate(LocalDate.parse(leftDate));
}
if (status == EmpStatus.RESIGNED && leftDate != null) {
employee.setLeftDate(LocalDate.parse(leftDate));
}
return employeeRepository.save(employee);
}
@Transactional
public Employee updateRole(Long empId, RoleCode role) {
Employee employee = findById(empId);
employee.setRoleCode(role);
return employeeRepository.save(employee);
}
@Transactional
public Employee updateDispatchStatus(Long empId, DispatchStatus status) {
Employee employee = findById(empId);
employee.setDispatchStatus(status);
return employeeRepository.save(employee);
}
@Transactional @Transactional
public void delete(Long empId) { public void delete(Long empId) {
Employee employee = findById(empId); Employee employee = findById(empId);
File diff suppressed because it is too large Load Diff
+9
View File
@@ -225,6 +225,15 @@ export interface EquipmentAssignment {
returnedDate: string | null; returnedDate: string | null;
condOnAssign: string; condOnAssign: string;
condOnReturn: string | null; condOnReturn: string | null;
equipment?: {
equipmentId: number;
assetCode: string;
manufacturer: string;
modelName: string;
serialNumber: string;
equipmentType: string;
status: string;
};
} }
export interface EquipmentMaintenance { export interface EquipmentMaintenance {