Files
sam-manage/resources/views/bending/base/partials/table.blade.php
김보곤 cd06925b87 fix: [bending] API 연결 실패 시 안내 메시지 표시
- API 401/403/연결실패 시 구체적인 안내 메시지 표시
- 데이터 없음과 API 오류를 구분하여 사용자에게 안내
2026-03-21 09:48:03 +09:00

180 lines
11 KiB
PHP

@php
$itemList = $items['data'] ?? $items ?? [];
$total = $items['total'] ?? count($itemList);
$currentPage = $items['current_page'] ?? 1;
$lastPage = $items['last_page'] ?? 1;
@endphp
<div class="overflow-x-auto bg-white rounded-lg shadow-sm mt-4">
<table class="min-w-full text-sm">
<thead class="bg-gray-50 border-b">
<tr>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">NO</th>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">코드</th>
<th class="px-2 py-2 text-center text-sm font-semibold text-gray-700">대분류</th>
<th class="px-2 py-2 text-center text-sm font-semibold text-gray-700">인정</th>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">분류</th>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">품명</th>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">규격</th>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">재질</th>
<th class="px-2 py-2 text-center text-sm font-semibold text-gray-700">이미지</th>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">모델</th>
<th class="px-2 py-2 text-right text-sm font-semibold text-gray-700">폭합</th>
<th class="px-2 py-2 text-center text-sm font-semibold text-gray-700">절곡수</th>
<th class="px-2 py-2 text-left text-sm font-semibold text-gray-700">등록일</th>
<th class="px-2 py-2 text-center text-sm font-semibold text-gray-700">수정자</th>
<th class="px-2 py-2 text-center text-sm font-semibold text-gray-700">작업</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
@forelse($itemList as $item)
@php
$itemSep = $item['item_sep'] ?? '-';
$widthSum = $item['width_sum'] ?? null;
$bendCount = $item['bend_count'] ?? 0;
$modelUA = $item['model_UA'] ?? null;
$createdAt = $item['created_at'] ?? null;
@endphp
<tr class="hover:bg-blue-50 cursor-pointer" onclick="window.location='{{ route('bending.base.show', $item['id']) }}'">
<td class="px-2 py-2 text-gray-500 text-xs">{{ $item['id'] }}</td>
<td class="px-2 py-2 font-mono text-xs">{{ $item['code'] }}</td>
<td class="px-2 py-2 text-center">
<span class="px-1.5 py-0.5 rounded text-xs {{ $itemSep === '스크린' ? 'bg-blue-100 text-blue-700' : 'bg-orange-100 text-orange-700' }}">
{{ $itemSep }}
</span>
</td>
<td class="px-2 py-2 text-center text-xs">
@if($modelUA)
<span class="{{ $modelUA === '인정' ? 'text-green-600' : 'text-gray-400' }}">{{ $modelUA }}</span>
@else
<span class="text-gray-300">-</span>
@endif
</td>
<td class="px-2 py-2 text-xs">{{ $item['item_bending'] ?? '-' }}</td>
<td class="px-2 py-2 font-medium text-xs">{{ $item['item_name'] ?? $item['name'] }}</td>
<td class="px-2 py-2 text-gray-600 text-xs">{{ $item['item_spec'] ?? '-' }}</td>
<td class="px-2 py-2 text-gray-600 text-xs">{{ $item['material'] ?? '-' }}</td>
<td class="px-2 py-2 text-center">
@if(!empty($item['image_file_id']))
<div class="relative inline-block img-preview-wrap">
<img src="{{ $item['image_url'] ?? route('files.view', $item['image_file_id']) }}" width="24" height="24" style="width:24px; height:24px; object-fit:contain;" class="rounded inline-block" alt="">
<div class="img-preview-popup hidden absolute z-50 bg-white border shadow-xl rounded-lg p-1" style="left:50%; transform:translateX(-50%); width:300px;">
<img src="{{ $item['image_url'] ?? route('files.view', $item['image_file_id']) }}" class="w-full rounded" alt="">
</div>
</div>
@else
<span class="text-gray-300">-</span>
@endif
</td>
<td class="px-2 py-2 text-gray-600 text-xs">{{ $item['model_name'] ?? '-' }}</td>
<td class="px-2 py-2 text-right font-mono text-xs">{{ $widthSum ?? '-' }}</td>
<td class="px-2 py-2 text-center text-xs">
@if($bendCount > 0)
<span class="text-blue-600 font-medium">{{ $bendCount }}</span>
@else
<span class="text-gray-300">-</span>
@endif
</td>
<td class="px-2 py-2 text-gray-500 text-xs">{{ $createdAt ? \Illuminate\Support\Str::before($createdAt, ' ') : '-' }}</td>
<td class="px-2 py-2 text-center text-xs text-gray-500">{{ $item['modified_by'] ?? '-' }}</td>
<td class="px-2 py-2 text-center">
<a href="{{ route('bending.base.edit', $item['id']) }}" class="text-blue-600 hover:underline text-xs"
onclick="event.stopPropagation()">수정</a>
</td>
</tr>
@empty
<tr>
<td colspan="15" class="px-3 py-8 text-center">
@if(!empty($apiError))
<div class="text-amber-600">
<svg class="w-8 h-8 mx-auto mb-2 text-amber-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.082 16.5c-.77.833.192 2.5 1.732 2.5z"/>
</svg>
<p class="text-sm font-medium">{{ $apiError }}</p>
</div>
@else
<span class="text-gray-400">데이터가 없습니다.</span>
@endif
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<script>
document.querySelectorAll('.img-preview-wrap').forEach(wrap => {
const popup = wrap.querySelector('.img-preview-popup');
if (!popup) return;
popup.style.position = 'fixed';
wrap.addEventListener('mouseenter', () => {
const rect = wrap.getBoundingClientRect();
const popW = 300;
let left = rect.left + rect.width / 2 - popW / 2;
if (left < 4) left = 4;
if (left + popW > window.innerWidth - 4) left = window.innerWidth - popW - 4;
popup.style.left = left + 'px';
popup.style.width = popW + 'px';
popup.style.transform = 'none';
if (rect.top > window.innerHeight / 2) {
popup.style.bottom = (window.innerHeight - rect.top + 4) + 'px';
popup.style.top = 'auto';
} else {
popup.style.top = (rect.bottom + 4) + 'px';
popup.style.bottom = 'auto';
}
popup.classList.remove('hidden');
});
wrap.addEventListener('mouseleave', () => { popup.classList.add('hidden'); });
});
</script>
{{-- 페이지네이션 --}}
@if($lastPage > 1)
<div class="bg-white px-4 py-3 mt-4 rounded-lg shadow-sm">
<div class="flex items-center justify-between">
<p class="text-sm text-gray-700">전체 <span class="font-medium">{{ $total }}</span></p>
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px">
@if($currentPage > 1)
<a href="{{ request()->fullUrlWithQuery(['page' => 1]) }}" class="relative inline-flex items-center px-3 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">처음</a>
<a href="{{ request()->fullUrlWithQuery(['page' => $currentPage - 1]) }}" class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>
</a>
@else
<span class="relative inline-flex items-center px-3 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed">처음</span>
<span class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"/></svg>
</span>
@endif
@php
$maxPages = 10;
$startPage = max(1, $currentPage - floor($maxPages / 2));
$endPage = min($lastPage, $startPage + $maxPages - 1);
if ($endPage - $startPage + 1 < $maxPages) { $startPage = max(1, $endPage - $maxPages + 1); }
@endphp
@for($p = $startPage; $p <= $endPage; $p++)
@if($p == $currentPage)
<span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-blue-50 text-sm font-medium text-blue-600">{{ $p }}</span>
@else
<a href="{{ request()->fullUrlWithQuery(['page' => $p]) }}" class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50">{{ $p }}</a>
@endif
@endfor
@if($currentPage < $lastPage)
<a href="{{ request()->fullUrlWithQuery(['page' => $currentPage + 1]) }}" class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/></svg>
</a>
<a href="{{ request()->fullUrlWithQuery(['page' => $lastPage]) }}" class="relative inline-flex items-center px-3 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"></a>
@else
<span class="relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed">
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"/></svg>
</span>
<span class="relative inline-flex items-center px-3 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-300 cursor-not-allowed"></span>
@endif
</nav>
</div>
</div>
@endif