feat:계약 휴지통 기능 (소프트 삭제/복구/영구삭제)
백엔드: - destroy를 SoftDelete 방식으로 변경 (deleted_at + deleted_by 기록) - trashed: 휴지통 목록 조회 API 추가 - restore: 선택 복구 API 추가 - forceDestroy: 영구 삭제 API 추가 (파일+관련 레코드 완전 삭제) - 라우트 3개 추가 (trashed, restore, force-destroy) 프론트엔드: - 대시보드에 탭 UI 추가 (계약 목록 / 휴지통) - 휴지통 탭: 삭제된 계약 목록, 삭제일 표시 - 선택 복구(파란색) / 영구삭제(빨간색) 버튼 - 휴지통 건수 뱃지 표시 - 삭제 시 메시지를 "휴지통으로 이동"으로 변경 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -220,7 +220,7 @@ public function cancel(Request $request, int $id): JsonResponse
|
||||
}
|
||||
|
||||
/**
|
||||
* 계약 삭제 (단건/복수)
|
||||
* 계약 삭제 - 휴지통으로 이동 (SoftDelete)
|
||||
*/
|
||||
public function destroy(Request $request): JsonResponse
|
||||
{
|
||||
@@ -247,6 +247,95 @@ public function destroy(Request $request): JsonResponse
|
||||
], 422);
|
||||
}
|
||||
|
||||
$deletedCount = 0;
|
||||
foreach ($contracts as $contract) {
|
||||
$contract->update(['deleted_by' => auth()->id()]);
|
||||
$contract->delete(); // SoftDelete → deleted_at 설정
|
||||
$deletedCount++;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => "{$deletedCount}건의 계약이 휴지통으로 이동되었습니다.",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 휴지통 목록
|
||||
*/
|
||||
public function trashed(Request $request): JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$query = EsignContract::onlyTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->with(['signers:id,contract_id,name,role,status']);
|
||||
|
||||
if ($search = $request->input('search')) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('title', 'like', "%{$search}%")
|
||||
->orWhere('contract_code', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
$perPage = $request->input('per_page', 20);
|
||||
$data = $query->orderBy('deleted_at', 'desc')->paginate($perPage);
|
||||
|
||||
return response()->json(['success' => true, 'data' => $data]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 휴지통에서 복구
|
||||
*/
|
||||
public function restore(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'ids' => 'required|array|min:1',
|
||||
'ids.*' => 'required|integer',
|
||||
]);
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$contracts = EsignContract::onlyTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereIn('id', $request->input('ids'))
|
||||
->get();
|
||||
|
||||
if ($contracts->isEmpty()) {
|
||||
return response()->json(['success' => false, 'message' => '복구할 계약을 찾을 수 없습니다.'], 404);
|
||||
}
|
||||
|
||||
$restoredCount = 0;
|
||||
foreach ($contracts as $contract) {
|
||||
$contract->update(['deleted_by' => null]);
|
||||
$contract->restore();
|
||||
$restoredCount++;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => "{$restoredCount}건의 계약이 복구되었습니다.",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 영구 삭제
|
||||
*/
|
||||
public function forceDestroy(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'ids' => 'required|array|min:1',
|
||||
'ids.*' => 'required|integer',
|
||||
]);
|
||||
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$contracts = EsignContract::onlyTrashed()
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereIn('id', $request->input('ids'))
|
||||
->get();
|
||||
|
||||
if ($contracts->isEmpty()) {
|
||||
return response()->json(['success' => false, 'message' => '삭제할 계약을 찾을 수 없습니다.'], 404);
|
||||
}
|
||||
|
||||
$deletedCount = 0;
|
||||
foreach ($contracts as $contract) {
|
||||
// 관련 파일 삭제
|
||||
@@ -265,17 +354,17 @@ public function destroy(Request $request): JsonResponse
|
||||
}
|
||||
}
|
||||
|
||||
// 관련 레코드 삭제
|
||||
// 관련 레코드 영구 삭제
|
||||
EsignSignField::where('contract_id', $contract->id)->delete();
|
||||
EsignAuditLog::where('contract_id', $contract->id)->delete();
|
||||
EsignSigner::withoutGlobalScopes()->where('contract_id', $contract->id)->delete();
|
||||
$contract->delete();
|
||||
$contract->forceDelete();
|
||||
$deletedCount++;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => "{$deletedCount}건의 계약이 삭제되었습니다.",
|
||||
'message' => "{$deletedCount}건의 계약이 영구 삭제되었습니다.",
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user