diff --git a/app/Services/ArchivedRecordService.php b/app/Services/ArchivedRecordService.php index 6f3cb1a7..1ca5712c 100644 --- a/app/Services/ArchivedRecordService.php +++ b/app/Services/ArchivedRecordService.php @@ -12,12 +12,14 @@ class ArchivedRecordService /** * 아카이브 레코드 목록 조회 (batch_id로 그룹핑, 페이지네이션) * batch_id가 NULL인 기존 데이터는 각각 개별 batch로 취급 + * + * NOTE: GROUP BY + paginate() 조합 시 total count가 잘못 계산되는 문제 해결 + * 서브쿼리로 GROUP BY 결과를 감싼 후 외부에서 paginate() 실행 */ public function getArchivedRecordsBatched(array $filters = [], int $perPage = 15): LengthAwarePaginator { - // batch_id별로 그룹핑하여 첫 번째 레코드만 조회 - // batch_id가 NULL인 경우 id를 기반으로 가상 batch_id 생성 - $query = ArchivedRecord::query() + // 1. 서브쿼리: batch_id별 그룹핑 + $subQuery = ArchivedRecord::query() ->select([ DB::raw("COALESCE(batch_id, CONCAT('legacy_', id)) as batch_id"), DB::raw("COALESCE(batch_description, CONCAT(record_type, ' 삭제 (ID: ', original_id, ')')) as batch_description"), @@ -27,22 +29,29 @@ public function getArchivedRecordsBatched(array $filters = [], int $perPage = 15 DB::raw('MIN(deleted_by) as deleted_by'), DB::raw('MIN(deleted_at) as deleted_at'), ]) - ->groupBy(DB::raw("COALESCE(batch_id, CONCAT('legacy_', id))"), DB::raw("COALESCE(batch_description, CONCAT(record_type, ' 삭제 (ID: ', original_id, ')'))")); + ->groupBy( + DB::raw("COALESCE(batch_id, CONCAT('legacy_', id))"), + DB::raw("COALESCE(batch_description, CONCAT(record_type, ' 삭제 (ID: ', original_id, ')'))") + ); + + // 2. 외부 쿼리: 서브쿼리를 감싸서 정확한 count 계산 + $query = DB::table(DB::raw("({$subQuery->toSql()}) as grouped")) + ->mergeBindings($subQuery->getQuery()) + ->select('*'); // 레코드 타입 필터 if (! empty($filters['record_type'])) { - $query->having('record_types', 'like', "%{$filters['record_type']}%"); + $query->where('record_types', 'like', "%{$filters['record_type']}%"); } // 삭제자 필터 if (! empty($filters['deleted_by'])) { - $query->having('deleted_by', $filters['deleted_by']); + $query->where('deleted_by', $filters['deleted_by']); } // 검색 if (! empty($filters['search'])) { - $search = $filters['search']; - $query->where('batch_description', 'like', "%{$search}%"); + $query->where('batch_description', 'like', "%{$filters['search']}%"); } // 정렬 (기본: 삭제일시 내림차순) @@ -50,7 +59,11 @@ public function getArchivedRecordsBatched(array $filters = [], int $perPage = 15 $sortDirection = $filters['sort_direction'] ?? 'desc'; $query->orderBy($sortBy, $sortDirection); - return $query->paginate($perPage); + // NOTE: DB::table() 사용 시 request의 page 파라미터를 자동으로 읽지 못함 + // filters에서 page를 명시적으로 전달 + $page = $filters['page'] ?? null; + + return $query->paginate($perPage, ['*'], 'page', $page); } /** diff --git a/resources/views/archived-records/partials/table.blade.php b/resources/views/archived-records/partials/table.blade.php index 49483942..d8ba8b33 100644 --- a/resources/views/archived-records/partials/table.blade.php +++ b/resources/views/archived-records/partials/table.blade.php @@ -74,57 +74,9 @@ class="text-blue-600 hover:text-blue-900 transition" -{{-- 페이지네이션 --}} -@if($records->hasPages()) -
-
-
- 총 {{ $records->total() }}개 작업 중 - {{ $records->firstItem() }} - - {{ $records->lastItem() }}개 표시 -
-
- {{-- 이전 페이지 --}} - @if($records->onFirstPage()) - 이전 - @else - - @endif - - {{-- 페이지 번호 --}} - @foreach(range(max(1, $records->currentPage() - 2), min($records->lastPage(), $records->currentPage() + 2)) as $page) - @if($page == $records->currentPage()) - {{ $page }} - @else - - @endif - @endforeach - - {{-- 다음 페이지 --}} - @if($records->hasMorePages()) - - @else - 다음 - @endif -
-
-
-@endif +{{-- 페이지네이션 (공용 컴포넌트) --}} +@include('partials.pagination', [ + 'paginator' => $records, + 'target' => '#archived-record-table', + 'includeForm' => '#filterForm' +])