feat: [hr] 사원관리 퇴직자 영구삭제 기능 추가

- 슈퍼관리자만 퇴직 상태 사원을 영구삭제 가능
- 관련 첨부파일도 함께 삭제
- DELETE /admin/hr/employees/{id}/force 엔드포인트 추가
This commit is contained in:
김보곤
2026-03-03 21:46:37 +09:00
parent 614cbaef15
commit 81b64f25aa
4 changed files with 81 additions and 0 deletions

View File

@@ -263,6 +263,43 @@ public function destroy(Request $request, int $id): JsonResponse|Response
}
}
/**
* 사원 영구삭제 (퇴직자만, 슈퍼관리자 전용)
*/
public function forceDestroy(Request $request, int $id): JsonResponse|Response
{
if (! auth()->user()?->is_super_admin) {
return response()->json([
'success' => false,
'message' => '슈퍼관리자만 영구삭제할 수 있습니다.',
], 403);
}
try {
$result = $this->employeeService->forceDeleteEmployee($id);
if (! $result['success']) {
return response()->json($result, 422);
}
if ($request->header('HX-Request')) {
$employees = $this->employeeService->getEmployees($request->all(), $request->integer('per_page', 20));
return response(view('hr.employees.partials.table', compact('employees')));
}
return response()->json($result);
} catch (\Throwable $e) {
report($e);
return response()->json([
'success' => false,
'message' => '영구삭제 중 오류가 발생했습니다.',
'error' => config('app.debug') ? $e->getMessage() : null,
], 500);
}
}
/**
* 사원 첨부파일 업로드 (로컬 + GCS 듀얼 저장)
*/

View File

@@ -366,6 +366,34 @@ public function deleteEmployee(int $id): bool
return true;
}
/**
* 사원 영구 삭제 (퇴직자만, 슈퍼관리자 전용)
*/
public function forceDeleteEmployee(int $id): array
{
$employee = $this->getEmployeeById($id);
if (! $employee) {
return ['success' => false, 'message' => '사원 정보를 찾을 수 없습니다.'];
}
if ($employee->employee_status !== 'resigned') {
return ['success' => false, 'message' => '퇴직 상태인 사원만 영구삭제할 수 있습니다.'];
}
$name = $employee->display_name ?? $employee->user?->name ?? '알 수 없음';
// 관련 첨부파일 삭제
\App\Models\Boards\File::where('document_type', 'employee_profile')
->where('document_id', $employee->id)
->where('tenant_id', session('selected_tenant_id'))
->delete();
// tenant_user_profiles 레코드 영구 삭제
$employee->delete();
return ['success' => true, 'message' => "사원 '{$name}'이(가) 영구삭제되었습니다."];
}
/**
* 부서 목록 (드롭다운용)
*/

View File

@@ -143,6 +143,21 @@ class="text-red-600 hover:text-red-800" title="퇴직처리">
</svg>
</button>
@endif
{{-- 영구삭제 (퇴직자 + 슈퍼관리자만) --}}
@if($employee->employee_status === 'resigned' && auth()->user()?->is_super_admin)
<button type="button"
hx-delete="{{ route('api.admin.hr.employees.force-destroy', $employee->id) }}"
hx-headers='{"X-CSRF-TOKEN": "{{ csrf_token() }}"}'
hx-target="#employees-table"
hx-swap="innerHTML"
hx-confirm="⚠️ {{ $employee->display_name ?? $employee->user?->name }}님의 사원 정보를 영구삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
class="text-red-400 hover:text-red-600" title="영구삭제">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
</svg>
</button>
@endif
</div>
</td>
</tr>

View File

@@ -1141,6 +1141,7 @@
Route::get('/{id}', [\App\Http\Controllers\Api\Admin\HR\EmployeeController::class, 'show'])->name('show');
Route::put('/{id}', [\App\Http\Controllers\Api\Admin\HR\EmployeeController::class, 'update'])->name('update');
Route::delete('/{id}', [\App\Http\Controllers\Api\Admin\HR\EmployeeController::class, 'destroy'])->name('destroy');
Route::delete('/{id}/force', [\App\Http\Controllers\Api\Admin\HR\EmployeeController::class, 'forceDestroy'])->name('force-destroy');
// 첨부파일
Route::post('/{id}/files', [\App\Http\Controllers\Api\Admin\HR\EmployeeController::class, 'uploadFile'])->name('upload-file');