From cd06925b87c8f76a6279c00e88a2837c28da91c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Sat, 21 Mar 2026 09:43:57 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20[bending]=20API=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EC=8B=A4=ED=8C=A8=20=EC=8B=9C=20=EC=95=88=EB=82=B4=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - API 401/403/연결실패 시 구체적인 안내 메시지 표시 - 데이터 없음과 API 오류를 구분하여 사용자에게 안내 --- .../Controllers/BendingBaseController.php | 33 ++- .../Controllers/BendingProductController.php | 35 ++- .../bending/base/partials/table.blade.php | 179 +++++++++++++ .../bending/products/partials/table.blade.php | 235 ++++++++++++++++++ 4 files changed, 470 insertions(+), 12 deletions(-) create mode 100644 resources/views/bending/base/partials/table.blade.php create mode 100644 resources/views/bending/products/partials/table.blade.php diff --git a/app/Http/Controllers/BendingBaseController.php b/app/Http/Controllers/BendingBaseController.php index c12bf0ea..216f34a0 100644 --- a/app/Http/Controllers/BendingBaseController.php +++ b/app/Http/Controllers/BendingBaseController.php @@ -37,8 +37,27 @@ public function index(Request $request): View|\Illuminate\Http\Response $params = $request->only(['item_sep', 'item_bending', 'material', 'model_UA', 'item_name', 'search', 'page', 'size']); $params['size'] = $params['size'] ?? 30; - $response = $this->api()->get('/api/v1/bending-items', $params); - $body = $response->successful() ? $response->json('data', []) : []; + $apiError = null; + try { + $response = $this->api()->get('/api/v1/bending-items', $params); + } catch (\Illuminate\Http\Client\ConnectionException $e) { + $apiError = 'API 서버에 연결할 수 없습니다. API 서비스 상태를 확인해 주세요.'; + $response = null; + } + + if ($response && $response->successful()) { + $body = $response->json('data', []); + } else { + $body = []; + if (! $apiError && $response) { + $apiError = match ($response->status()) { + 401 => 'API 인증이 필요합니다. SAM 서비스에 로그인하여 API를 연결해 주세요.', + 403 => 'API 접근 권한이 없습니다. 관리자에게 문의해 주세요.', + default => "API 오류가 발생했습니다. (HTTP {$response->status()})", + }; + } + } + $data = [ 'data' => $body['data'] ?? [], 'total' => $body['total'] ?? 0, @@ -46,12 +65,15 @@ public function index(Request $request): View|\Illuminate\Http\Response 'last_page' => $body['last_page'] ?? 1, ]; - $filterResponse = $this->api()->get('/api/v1/bending-items/filters'); - $filterOptions = $filterResponse->successful() ? $filterResponse->json('data', []) : []; + $filterOptions = []; + if (! $apiError) { + $filterResponse = $this->api()->get('/api/v1/bending-items/filters'); + $filterOptions = $filterResponse->successful() ? $filterResponse->json('data', []) : []; + } if ($request->header('HX-Request')) { if ($request->header('HX-Target') === 'items-table') { - return view('bending.base.partials.table', ['items' => $data]); + return view('bending.base.partials.table', ['items' => $data, 'apiError' => $apiError]); } return response('', 200)->header('HX-Redirect', route('bending.base.index', $request->query())); @@ -60,6 +82,7 @@ public function index(Request $request): View|\Illuminate\Http\Response return view('bending.base.index', [ 'items' => $data, 'filterOptions' => $filterOptions, + 'apiError' => $apiError, ]); } diff --git a/app/Http/Controllers/BendingProductController.php b/app/Http/Controllers/BendingProductController.php index 761aaf8a..60c83390 100644 --- a/app/Http/Controllers/BendingProductController.php +++ b/app/Http/Controllers/BendingProductController.php @@ -49,8 +49,27 @@ public function index(Request $request, string $category = 'GUIDERAIL_MODEL'): V $params['size'] = $params['size'] ?? 30; $params['item_category'] = $category; - $response = $this->api()->get('/api/v1/guiderail-models', $params); - $body = $response->successful() ? $response->json('data', []) : []; + $apiError = null; + try { + $response = $this->api()->get('/api/v1/guiderail-models', $params); + } catch (\Illuminate\Http\Client\ConnectionException $e) { + $apiError = 'API 서버에 연결할 수 없습니다. API 서비스 상태를 확인해 주세요.'; + $response = null; + } + + if ($response && $response->successful()) { + $body = $response->json('data', []); + } else { + $body = []; + if (! $apiError && $response) { + $apiError = match ($response->status()) { + 401 => 'API 인증이 필요합니다. SAM 서비스에 로그인하여 API를 연결해 주세요.', + 403 => 'API 접근 권한이 없습니다. 관리자에게 문의해 주세요.', + default => "API 오류가 발생했습니다. (HTTP {$response->status()})", + }; + } + } + $data = [ 'data' => $body['data'] ?? [], 'total' => $body['total'] ?? 0, @@ -58,16 +77,17 @@ public function index(Request $request, string $category = 'GUIDERAIL_MODEL'): V 'last_page' => $body['last_page'] ?? 1, ]; - $filterResponse = $this->api()->get('/api/v1/guiderail-models/filters'); - $filterOptions = $filterResponse->successful() ? $filterResponse->json('data', []) : []; + $filterOptions = []; + if (! $apiError) { + $filterResponse = $this->api()->get('/api/v1/guiderail-models/filters'); + $filterOptions = $filterResponse->successful() ? $filterResponse->json('data', []) : []; + } if ($request->header('HX-Request')) { - // 필터/검색 HTMX (hx-target="#items-table") → 파셜 반환 if ($request->header('HX-Target') === 'items-table') { - return view('bending.products.partials.table', ['items' => $data, 'config' => $config, 'category' => $category]); + return view('bending.products.partials.table', ['items' => $data, 'config' => $config, 'category' => $category, 'apiError' => $apiError]); } - // 사이드바 등 그 외 HTMX → 전체 페이지 리로드 return response('', 200)->header('HX-Redirect', route("bending.{$config['prefix']}.index", $request->query())); } @@ -76,6 +96,7 @@ public function index(Request $request, string $category = 'GUIDERAIL_MODEL'): V 'filterOptions' => $filterOptions, 'config' => $config, 'category' => $category, + 'apiError' => $apiError, ]); } diff --git a/resources/views/bending/base/partials/table.blade.php b/resources/views/bending/base/partials/table.blade.php new file mode 100644 index 00000000..a70655ee --- /dev/null +++ b/resources/views/bending/base/partials/table.blade.php @@ -0,0 +1,179 @@ +@php + $itemList = $items['data'] ?? $items ?? []; + $total = $items['total'] ?? count($itemList); + $currentPage = $items['current_page'] ?? 1; + $lastPage = $items['last_page'] ?? 1; +@endphp + +
+ + + + + + + + + + + + + + + + + + + + + + @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 + + + + + + + + + + + + + + + + + + @empty + + + + @endforelse + +
NO코드대분류인정분류품명규격재질이미지모델폭합절곡수등록일수정자작업
{{ $item['id'] }}{{ $item['code'] }} + + {{ $itemSep }} + + + @if($modelUA) + {{ $modelUA }} + @else + - + @endif + {{ $item['item_bending'] ?? '-' }}{{ $item['item_name'] ?? $item['name'] }}{{ $item['item_spec'] ?? '-' }}{{ $item['material'] ?? '-' }} + @if(!empty($item['image_file_id'])) +
+ + +
+ @else + - + @endif +
{{ $item['model_name'] ?? '-' }}{{ $widthSum ?? '-' }} + @if($bendCount > 0) + {{ $bendCount }} + @else + - + @endif + {{ $createdAt ? \Illuminate\Support\Str::before($createdAt, ' ') : '-' }}{{ $item['modified_by'] ?? '-' }} + 수정 +
+ @if(!empty($apiError)) +
+ + + +

{{ $apiError }}

+
+ @else + 데이터가 없습니다. + @endif +
+
+ + + +{{-- 페이지네이션 --}} +@if($lastPage > 1) +
+
+

전체 {{ $total }}

+ +
+
+@endif diff --git a/resources/views/bending/products/partials/table.blade.php b/resources/views/bending/products/partials/table.blade.php new file mode 100644 index 00000000..8534e71f --- /dev/null +++ b/resources/views/bending/products/partials/table.blade.php @@ -0,0 +1,235 @@ +@php + $itemList = $items['data'] ?? []; + $total = $items['total'] ?? count($itemList); + $currentPage = $items['current_page'] ?? 1; + $lastPage = $items['last_page'] ?? 1; + $cat = $category ?? ($config['category'] ?? 'GUIDERAIL_MODEL'); + $isCase = $cat === 'SHUTTERBOX_MODEL'; + $isBottom = $cat === 'BOTTOMBAR_MODEL'; + $isGuiderail = !$isCase && !$isBottom; +@endphp + +
+ + + + + @if($isCase) + + + + + @elseif($isBottom) + + + + + + @else + + + + + + + @endif + + + + + + + + + + + @forelse($itemList as $item) + @php + $itemCat = $item['item_category'] ?? 'GUIDERAIL_MODEL'; + $routePrefix = match($itemCat) { 'SHUTTERBOX_MODEL' => 'cases', 'BOTTOMBAR_MODEL' => 'bottombars', default => 'products' }; + @endphp + + + @if($isCase) + + + + + @elseif($isBottom) + + + + + + @else + + + + + + + @endif + + + + + + + + + @empty + + + + @endforelse + +
NO박스(가로×세로)점검구전면밑레일폭모델명대분류인정가로×세로마감모델명대분류인정형상레일폭×높이마감이미지부품수소요자재량검색어수정자작업지시서작업
{{ $item['id'] }} + {{ $item['box_width'] ?? '-' }}×{{ $item['box_height'] ?? '-' }} + {{ $item['exit_direction'] ?? '-' }}{{ $item['front_bottom_width'] ?? '-' }}{{ $item['rail_width'] ?? '-' }}{{ $item['model_name'] ?? $item['name'] }} + @php $sep = $item['item_sep'] ?? '-'; @endphp + {{ $sep }} + + @if($item['model_UA'] ?? null) + {{ $item['model_UA'] }} + @else - @endif + {{ ($item['bar_width'] ?? '-') }}×{{ ($item['bar_height'] ?? '-') }}{{ $item['finishing_type'] ?? '-' }}{{ $item['model_name'] ?? $item['name'] }} + @php $sep = $item['item_sep'] ?? '-'; @endphp + {{ $sep }} + + @if($item['model_UA'] ?? null) + {{ $item['model_UA'] }} + @else - @endif + {{ $item['check_type'] ?? '-' }}{{ ($item['rail_width'] ?? '-') }}×{{ ($item['rail_length'] ?? '-') }}{{ $item['finishing_type'] ?? '-' }} + @if(!empty($item['image_file_id'])) +
+ + +
+ @else + - + @endif +
+ {{ $item['component_count'] ?? 0 }} + + @foreach(($item['material_summary'] ?? []) as $mat => $total) + {{ $mat }}: {{ $total }} + @if(!$loop->last) | @endif + @endforeach + @if(empty($item['material_summary'])) - @endif + {{ $item['search_keyword'] ?? '-' }}{{ $item['modified_by'] ?? '-' }} + @if(!empty($item['id'])) + + @endif + + 수정 +
+ @if(!empty($apiError)) +
+ + + +

{{ $apiError }}

+
+ @else + 데이터가 없습니다. + @endif +
+
+ + + +{{-- 작업지시서 모달 (iframe 방식) --}} + +
+ 작업지시서 +
+ + +
+
+ +
+ + + +@if($lastPage > 1) +
+
+

전체 {{ $total }}

+ +
+
+@endif