diff --git a/app/Http/Controllers/Api/Admin/ArchivedRecordController.php b/app/Http/Controllers/Api/Admin/ArchivedRecordController.php index 7996869a..ecd9190e 100644 --- a/app/Http/Controllers/Api/Admin/ArchivedRecordController.php +++ b/app/Http/Controllers/Api/Admin/ArchivedRecordController.php @@ -14,11 +14,11 @@ public function __construct( ) {} /** - * 아카이브 레코드 목록 조회 + * 아카이브 레코드 목록 조회 (batch 그룹핑) */ public function index(Request $request): JsonResponse { - $records = $this->archivedRecordService->getArchivedRecords( + $records = $this->archivedRecordService->getArchivedRecordsBatched( $request->all(), $request->integer('per_page', 15) ); @@ -46,13 +46,13 @@ public function index(Request $request): JsonResponse } /** - * 특정 아카이브 레코드 조회 + * 특정 batch의 레코드 조회 */ - public function show(Request $request, int $id): JsonResponse + public function show(Request $request, string $batchId): JsonResponse { - $record = $this->archivedRecordService->getArchivedRecordById($id); + $records = $this->archivedRecordService->getRecordsByBatchId($batchId); - if (! $record) { + if ($records->isEmpty()) { return response()->json([ 'success' => false, 'message' => '아카이브 레코드를 찾을 수 없습니다.', @@ -62,13 +62,13 @@ public function show(Request $request, int $id): JsonResponse // HTMX 요청 시 HTML 반환 if ($request->header('HX-Request')) { return response()->json([ - 'html' => view('archived-records.partials.detail', compact('record'))->render(), + 'html' => view('archived-records.partials.detail', compact('records'))->render(), ]); } return response()->json([ 'success' => true, - 'data' => $record, + 'data' => $records, ]); } diff --git a/app/Http/Controllers/ArchivedRecordController.php b/app/Http/Controllers/ArchivedRecordController.php index bb4be804..8c62f68b 100644 --- a/app/Http/Controllers/ArchivedRecordController.php +++ b/app/Http/Controllers/ArchivedRecordController.php @@ -22,16 +22,25 @@ public function index(): View } /** - * 아카이브 레코드 상세 보기 (Blade 화면만) + * 아카이브 레코드 상세 보기 (batch 기준) */ - public function show(int $id): View + public function show(string $batchId): View { - $record = $this->archivedRecordService->getArchivedRecordById($id); + $records = $this->archivedRecordService->getRecordsByBatchId($batchId); - if (! $record) { + if ($records->isEmpty()) { abort(404, '아카이브 레코드를 찾을 수 없습니다.'); } - return view('archived-records.show', compact('record')); + // 첫 번째 레코드에서 batch 정보 추출 + $batchInfo = [ + 'batch_id' => $batchId, + 'batch_description' => $records->first()->batch_description, + 'deleted_by' => $records->first()->deletedByUser?->name ?? '-', + 'deleted_at' => $records->first()->deleted_at, + 'record_count' => $records->count(), + ]; + + return view('archived-records.show', compact('records', 'batchInfo')); } } diff --git a/app/Models/Archives/ArchivedRecord.php b/app/Models/Archives/ArchivedRecord.php index 9f908f0b..280ec754 100644 --- a/app/Models/Archives/ArchivedRecord.php +++ b/app/Models/Archives/ArchivedRecord.php @@ -12,6 +12,8 @@ class ArchivedRecord extends Model protected $table = 'archived_records'; protected $fillable = [ + 'batch_id', + 'batch_description', 'record_type', 'original_id', 'main_data', diff --git a/app/Services/ArchivedRecordService.php b/app/Services/ArchivedRecordService.php index 5f3cf940..79f115a0 100644 --- a/app/Services/ArchivedRecordService.php +++ b/app/Services/ArchivedRecordService.php @@ -4,48 +4,43 @@ use App\Models\Archives\ArchivedRecord; use Illuminate\Contracts\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; +use Illuminate\Support\Facades\DB; class ArchivedRecordService { /** - * 아카이브 레코드 목록 조회 (페이지네이션) + * 아카이브 레코드 목록 조회 (batch_id로 그룹핑, 페이지네이션) */ - public function getArchivedRecords(array $filters = [], int $perPage = 15): LengthAwarePaginator + public function getArchivedRecordsBatched(array $filters = [], int $perPage = 15): LengthAwarePaginator { + // batch_id별로 그룹핑하여 첫 번째 레코드만 조회 $query = ArchivedRecord::query() - ->with(['deletedByUser', 'relations']) - ->withCount('relations'); + ->select([ + 'batch_id', + 'batch_description', + DB::raw('MIN(id) as id'), + DB::raw('GROUP_CONCAT(DISTINCT record_type) as record_types'), + DB::raw('COUNT(*) as record_count'), + DB::raw('MIN(deleted_by) as deleted_by'), + DB::raw('MIN(deleted_at) as deleted_at'), + ]) + ->groupBy('batch_id', 'batch_description'); // 레코드 타입 필터 if (! empty($filters['record_type'])) { - $query->where('record_type', $filters['record_type']); + $query->having('record_types', 'like', "%{$filters['record_type']}%"); } // 삭제자 필터 if (! empty($filters['deleted_by'])) { - $query->where('deleted_by', $filters['deleted_by']); - } - - // 노트 유무 필터 - if (isset($filters['has_notes'])) { - if ($filters['has_notes'] === 'yes' || $filters['has_notes'] === '1') { - $query->whereNotNull('notes')->where('notes', '!=', ''); - } elseif ($filters['has_notes'] === 'no' || $filters['has_notes'] === '0') { - $query->where(function ($q) { - $q->whereNull('notes')->orWhere('notes', ''); - }); - } + $query->having('deleted_by', $filters['deleted_by']); } // 검색 if (! empty($filters['search'])) { $search = $filters['search']; - $query->where(function ($q) use ($search) { - $q->where('record_type', 'like', "%{$search}%") - ->orWhere('notes', 'like', "%{$search}%") - ->orWhereRaw("JSON_EXTRACT(main_data, '$.name') LIKE ?", ["%{$search}%"]) - ->orWhereRaw("JSON_EXTRACT(main_data, '$.title') LIKE ?", ["%{$search}%"]); - }); + $query->where('batch_description', 'like', "%{$search}%"); } // 정렬 (기본: 삭제일시 내림차순) @@ -56,6 +51,17 @@ public function getArchivedRecords(array $filters = [], int $perPage = 15): Leng return $query->paginate($perPage); } + /** + * 특정 batch의 모든 레코드 조회 + */ + public function getRecordsByBatchId(string $batchId): Collection + { + return ArchivedRecord::with(['deletedByUser', 'relations']) + ->where('batch_id', $batchId) + ->orderBy('id') + ->get(); + } + /** * 특정 아카이브 레코드 조회 */ @@ -65,6 +71,17 @@ public function getArchivedRecordById(int $id): ?ArchivedRecord ->find($id); } + /** + * batch_id로 첫 번째 레코드 조회 (상세 페이지 진입용) + */ + public function getFirstRecordByBatchId(string $batchId): ?ArchivedRecord + { + return ArchivedRecord::with(['deletedByUser', 'relations']) + ->where('batch_id', $batchId) + ->orderBy('id') + ->first(); + } + /** * 삭제자 목록 조회 (필터용) */ @@ -87,12 +104,10 @@ public function getDeletedByUsers(): array public function getStats(): array { return [ - 'total' => ArchivedRecord::count(), + 'total_batches' => ArchivedRecord::distinct('batch_id')->count('batch_id'), + 'total_records' => ArchivedRecord::count(), 'tenants' => ArchivedRecord::tenant()->count(), 'users' => ArchivedRecord::user()->count(), - 'with_notes' => ArchivedRecord::whereNotNull('notes') - ->where('notes', '!=', '') - ->count(), ]; } } diff --git a/resources/views/archived-records/index.blade.php b/resources/views/archived-records/index.blade.php index 8a32f2ae..0636faf9 100644 --- a/resources/views/archived-records/index.blade.php +++ b/resources/views/archived-records/index.blade.php @@ -46,7 +46,7 @@ class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none foc