diff --git a/app/Http/Controllers/DocumentController.php b/app/Http/Controllers/DocumentController.php index 15970add..3ddeba15 100644 --- a/app/Http/Controllers/DocumentController.php +++ b/app/Http/Controllers/DocumentController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers; use App\Models\Documents\Document; +use App\Models\Documents\DocumentData; use App\Models\DocumentTemplate; use App\Models\Items\Item; use Illuminate\Http\Request; @@ -100,6 +101,9 @@ public function edit(int $id): View|Response })->where('is_active', true)->orderBy('name')->get() : collect(); + // 기본정보 bf_ 자동 backfill (show 안 거치고 바로 edit 진입 대비) + $this->resolveAndBackfillBasicFields($document); + return view('documents.edit', [ 'document' => $document, 'template' => $document->template, @@ -128,8 +132,26 @@ public function print(int $id): View 'creator', ])->where('tenant_id', $tenantId)->findOrFail($id); + // 연결된 작업지시서의 work_order_items 로드 + $workOrderItems = collect(); + if ($document->linkable_type === 'work_order' && $document->linkable_id) { + $workOrderItems = DB::table('work_order_items') + ->where('work_order_id', $document->linkable_id) + ->orderBy('sort_order') + ->get() + ->map(function ($item) { + $item->options = json_decode($item->options, true) ?? []; + + return $item; + }); + } + + // 기본정보 bf_ 자동 backfill + $this->resolveAndBackfillBasicFields($document); + return view('documents.print', [ 'document' => $document, + 'workOrderItems' => $workOrderItems, ]); } @@ -154,11 +176,119 @@ public function show(int $id): View 'updater', ])->where('tenant_id', $tenantId)->findOrFail($id); + // 연결된 작업지시서의 work_order_items 로드 + $workOrderItems = collect(); + if ($document->linkable_type === 'work_order' && $document->linkable_id) { + $workOrderItems = DB::table('work_order_items') + ->where('work_order_id', $document->linkable_id) + ->orderBy('sort_order') + ->get() + ->map(function ($item) { + $item->options = json_decode($item->options, true) ?? []; + + return $item; + }); + } + + // 기본정보 bf_ 자동 backfill + $this->resolveAndBackfillBasicFields($document); + return view('documents.show', [ 'document' => $document, + 'workOrderItems' => $workOrderItems, ]); } + /** + * 기본정보(bf_) 레코드가 없으면 원본 데이터에서 resolve → document_data에 저장 + * React resolveFieldValue와 동일 매핑 로직 + */ + private function resolveAndBackfillBasicFields(Document $document): void + { + $basicFields = $document->template?->basicFields; + if (! $basicFields || $basicFields->isEmpty()) { + return; + } + + // bf_ 레코드가 하나라도 있으면 이미 저장된 것 → skip + $existingBfCount = $document->data + ->filter(fn ($d) => str_starts_with($d->field_key, 'bf_')) + ->count(); + if ($existingBfCount > 0) { + return; + } + + // 원본 데이터 로드: work_order + order + if ($document->linkable_type !== 'work_order' || ! $document->linkable_id) { + return; + } + + $workOrder = DB::table('work_orders')->find($document->linkable_id); + if (! $workOrder) { + return; + } + + $workOrderItems = DB::table('work_order_items') + ->where('work_order_id', $workOrder->id) + ->orderBy('sort_order') + ->get() + ->map(function ($item) { + $item->options = json_decode($item->options, true) ?? []; + + return $item; + }); + + $order = $workOrder->sales_order_id + ? DB::table('orders')->find($workOrder->sales_order_id) + : null; + + // 검사자 정보: work_order_items[0].options.inspection_data.inspected_by + $firstItem = $workOrderItems->first(); + $inspectionData = $firstItem?->options['inspection_data'] ?? []; + $inspectedBy = $inspectionData['inspected_by'] ?? null; + $inspectedAt = $inspectionData['inspected_at'] ?? null; + $inspectorName = $inspectedBy + ? DB::table('users')->where('id', $inspectedBy)->value('name') + : null; + + // field_key → 값 매핑 + $resolveMap = [ + 'product_name' => $firstItem?->item_name ?? '', + 'specification' => $firstItem?->specification ?? '', + 'lot_no' => $order?->order_no ?? '', + 'lot_size' => $workOrderItems->count().' 개소', + 'client' => $order?->client_name ?? '', + 'site_name' => $workOrder->project_name ?? '', + 'inspection_date' => $inspectedAt ? substr($inspectedAt, 0, 10) : now()->format('Y-m-d'), + 'inspector' => $inspectorName ?? '', + ]; + + // document_data에 bf_ 레코드 저장 + $records = []; + foreach ($basicFields as $field) { + $value = $resolveMap[$field->field_key] ?? $field->default_value ?? ''; + if ($value === '') { + continue; + } + $records[] = [ + 'document_id' => $document->id, + 'section_id' => null, + 'column_id' => null, + 'row_index' => 0, + 'field_key' => 'bf_'.$field->id, + 'field_value' => (string) $value, + 'created_at' => now(), + 'updated_at' => now(), + ]; + } + + if (! empty($records)) { + DocumentData::insert($records); + // 메모리의 data relation도 갱신 + $document->load('data'); + } + } + /** * 템플릿에 연결된 품목들의 규격 정보 (thickness, width, length) 조회 */ diff --git a/resources/views/documents/print.blade.php b/resources/views/documents/print.blade.php index 8d6a336e..1d1ff7c1 100644 --- a/resources/views/documents/print.blade.php +++ b/resources/views/documents/print.blade.php @@ -28,6 +28,23 @@ class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg transiti @php $template = $document->template; $hasComplexCol = $template->columns->contains(fn($c) => $c->column_type === 'complex' && $c->sub_labels); + + // 정규화 데이터 조회 헬퍼 + $getData = function($sectionId, $colId, $rowIdx, $fieldKey) use ($document) { + return $document->data + ->where('section_id', $sectionId) + ->where('column_id', $colId) + ->where('row_index', $rowIdx) + ->where('field_key', $fieldKey) + ->first()?->field_value ?? ''; + }; + // 레거시 fallback 헬퍼 + $getLegacyData = function($fieldKey) use ($document) { + return $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + }; + + // 컬럼 → 섹션 아이템 매핑 + $normalizeLabel = fn($label) => preg_replace('/[①②③④⑤⑥⑦⑧⑨⑩\s]/u', '', trim($label)); @endphp {{-- 섹션별 검사 테이블 --}} @@ -43,13 +60,58 @@ class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg transiti {{-- 검사 기준 이미지 --}} @if($section->image_path) + @php + $sectionImgUrl = preg_match('/^\d+\//', $section->image_path) + ? rtrim(config('app.api_url', 'http://api.sam.kr'), '/') . '/storage/tenants/' . $section->image_path + : asset('storage/' . $section->image_path); + @endphp
- {{ $section->title }} + {{ $section->title }}
@endif {{-- 검사 데이터 테이블 --}} @if($section->items->count() > 0 && $template->columns->count() > 0) + @php + // 컬럼 → 섹션 아이템 매핑 + 기준치 해석 + $allItems = $section->items; + $columnItemMap = []; + foreach ($template->columns as $col) { + $colKey = $normalizeLabel($col->label); + foreach ($allItems as $sItem) { + $itemKey = $normalizeLabel($sItem->item ?? $sItem->category ?? ''); + if ($itemKey === $colKey) { + $columnItemMap[$col->id] = $sItem; + break; + } + } + } + $resolveStandard = function($colId, $rowIndex) use ($columnItemMap, &$workOrderItems) { + $sItem = $columnItemMap[$colId] ?? null; + if (!$sItem) return ''; + $woItem = $workOrderItems[$rowIndex] ?? null; + if ($woItem) { + $fv = $sItem->field_values; + $refAttr = is_array($fv) ? ($fv['reference_attribute'] ?? null) : null; + if ($refAttr) { + $dimKey = $refAttr === 'length' ? 'width' : $refAttr; + $dimVal = $woItem->options[$dimKey] ?? null; + if ($dimVal) return (string) $dimVal; + } + } + $sc = $sItem->standard_criteria; + if ($sc) { + if (is_array($sc)) { + if (isset($sc['nominal'])) return (string) $sc['nominal']; + if (isset($sc['min'], $sc['max'])) return $sc['min'] . ' ~ ' . $sc['max']; + if (isset($sc['max'])) return '≤ ' . $sc['max']; + if (isset($sc['min'])) return '≥ ' . $sc['min']; + } + return (string) $sc; + } + return $sItem->standard ?? ''; + }; + @endphp {{-- 테이블 헤더 --}} @@ -86,33 +148,98 @@ class="doc-th" @endif - {{-- 테이블 바디 --}} + {{-- 테이블 바디 (정규화 형식: section_id + column_id + row_index + field_key) --}} - @foreach($section->items as $rowIndex => $item) + @php + $rowCount = $workOrderItems->isNotEmpty() + ? $workOrderItems->count() + : max(1, ($document->data->where('section_id', $section->id)->max('row_index') ?? 0) + 1); + @endphp + @for($rowIndex = 0; $rowIndex < $rowCount; $rowIndex++) @foreach($template->columns as $col) @if($col->column_type === 'complex' && $col->sub_labels) - {{-- complex: 서브 라벨별 측정값 --}} + @php + $inputIdx = 0; + $mappedItem = $columnItemMap[$col->id] ?? null; + $isOkng = $mappedItem?->measurement_type === 'checkbox'; + @endphp @foreach($col->sub_labels as $subIndex => $subLabel) @php - $fieldKey = "s{$section->id}_r{$rowIndex}_c{$col->id}_sub{$subIndex}"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $sl = strtolower($subLabel); + $isStandardSub = str_contains($sl, '도면') || str_contains($sl, '기준'); + $isOkNgSub = str_contains($sl, 'ok') || str_contains($sl, 'ng'); @endphp - + + @if($isStandardSub) + @php + $standardVal = $getData($section->id, $col->id, $rowIndex, 'standard'); + if (!$standardVal) $standardVal = $resolveStandard($col->id, $rowIndex); + @endphp + + @elseif($isOkNgSub) + @php + $n = $inputIdx + 1; + $okVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ok"); + $ngVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ng"); + $savedVal = $okVal === 'OK' ? 'OK' : ($ngVal === 'NG' ? 'NG' : ''); + if (!$savedVal) { + $valFallback = $getData($section->id, $col->id, $rowIndex, 'value'); + if (in_array(strtolower($valFallback), ['ok', 'pass', '적합', '합격'])) $savedVal = 'OK'; + elseif (in_array(strtolower($valFallback), ['ng', 'fail', '부적합'])) $savedVal = 'NG'; + } + $inputIdx++; + @endphp + + @else + @php + $n = $inputIdx + 1; + if ($isOkng) { + $okVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ok"); + $ngVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ng"); + $savedVal = $okVal === 'OK' ? 'OK' : ($ngVal === 'NG' ? 'NG' : ''); + if (!$savedVal) { + $valFallback = $getData($section->id, $col->id, $rowIndex, 'value'); + if (in_array(strtolower($valFallback), ['ok', 'pass', '적합', '합격'])) $savedVal = 'OK'; + elseif (in_array(strtolower($valFallback), ['ng', 'fail', '부적합'])) $savedVal = 'NG'; + } + } else { + $savedVal = $getData($section->id, $col->id, $rowIndex, "n{$n}"); + if (!$savedVal) $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + } + $inputIdx++; + @endphp + + @endif @endforeach @elseif($col->column_type === 'select') - {{-- select: 판정 --}} @php - $fieldKey = "s{$section->id}_r{$rowIndex}_c{$col->id}"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + if (!$savedVal) { + $rowJudgment = $document->data->where('field_key', 'row_judgment')->first()?->field_value ?? ''; + if (in_array(strtolower($rowJudgment), ['pass', 'ok', '적합'])) $savedVal = 'OK'; + elseif (in_array(strtolower($rowJudgment), ['fail', 'ng', '부적합'])) $savedVal = 'NG'; + } @endphp @elseif($col->column_type === 'check') - {{-- check: OK 체크 --}} @php - $fieldKey = "s{$section->id}_r{$rowIndex}_c{$col->id}"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); @endphp @elseif($col->column_type === 'measurement') - {{-- measurement: 수치 --}} @php - $fieldKey = "s{$section->id}_r{$rowIndex}_c{$col->id}"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'n1'); + if (!$savedVal) $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); @endphp @else - {{-- text: 정적 데이터 또는 입력 텍스트 --}} @php - $staticValue = match(true) { - str_contains(strtolower($col->label), 'no') && strlen($col->label) <= 4 => $rowIndex + 1, - in_array($col->label, ['검사항목', '항목']) => $item->getFieldValue('item'), - in_array($col->label, ['검사기준', '기준']) => $item->getFieldValue('standard'), - in_array($col->label, ['검사방식', '방식', '검사방법']) => $item->getFieldValue('method'), - in_array($col->label, ['검사주기', '주기']) => $item->getFieldValue('frequency'), - in_array($col->label, ['규격', '적용규격', '관련규정']) => $item->getFieldValue('regulation'), - in_array($col->label, ['분류', '카테고리']) => $item->getFieldValue('category'), - default => null, - }; + $label = trim($col->label); + $isNoCol = (str_contains(strtolower($label), 'no') && strlen($label) <= 4) + || in_array($label, ['일렬번호', '일련번호', '번호', '순번']); + $isJudgeCol = str_contains($label, '판정'); @endphp - @if($staticValue !== null) - + @elseif($isJudgeCol) + @php + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + if (!$savedVal) { + $rowJudgment = $document->data->where('field_key', 'row_judgment')->first()?->field_value ?? ''; + if (in_array(strtolower($rowJudgment), ['pass', 'ok', '적합'])) $savedVal = 'OK'; + elseif (in_array(strtolower($rowJudgment), ['fail', 'ng', '부적합'])) $savedVal = 'NG'; + } + @endphp + @else @php - $fieldKey = "s{$section->id}_r{$rowIndex}_c{$col->id}"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + if (!$savedVal) $savedVal = $getData($section->id, $col->id, $rowIndex, 'n1'); @endphp - @endforeach + @endfor
- {{ $savedVal ?: '-' }} - + {{ $standardVal ?: '-' }} + + @if($savedVal) + {{ strtoupper($savedVal) }} + @else + - + @endif + + @if($isOkng && $savedVal) + {{ strtoupper($savedVal) }} + @else + {{ $savedVal ?: '-' }} + @endif + @if($savedVal) - - {{ $savedVal }} + + {{ in_array(strtolower($savedVal), ['ok', 'pass', '적합', '합격', '적']) ? '적합' : '부적합' }} @else - @@ -120,51 +247,59 @@ class="doc-th" - @if($savedVal === 'OK') - OK + @if(in_array(strtolower($savedVal), ['ok', 'pass', '적합', '합격'])) + OK + @elseif($savedVal) + NG @else - @endif {{ $savedVal ?: '-' }} - {{ $staticValue }} + @if($isNoCol) + {{ $rowIndex + 1 }} + @if(in_array(strtolower($savedVal ?? ''), ['ok', 'pass', '적합', '합격'])) + OK + @elseif($savedVal) + NG + @else + - + @endif {{ $savedVal ?: '-' }} @@ -173,7 +308,7 @@ class="doc-th" @endif @endforeach
@endif @@ -191,7 +326,18 @@ class="doc-th" @php - $judgementVal = $document->data->where('field_key', 'footer_judgement')->first()?->field_value ?? ''; + $judgementVal = $document->data->where('field_key', 'overall_result')->first()?->field_value + ?? $document->data->where('field_key', 'footer_judgement')->first()?->field_value + ?? ''; + // fallback: overall_result 없으면 row_judgment에서 계산 + if (!$judgementVal) { + $rowJudgments = $document->data->where('field_key', 'row_judgment')->pluck('field_value'); + if ($rowJudgments->isNotEmpty()) { + $hasFail = $rowJudgments->contains(fn($v) => in_array(strtolower($v), ['fail', '부', '부적합', '불합격'])); + $allPass = $rowJudgments->every(fn($v) => in_array(strtolower($v), ['pass', '적', '적합', '합격'])); + $judgementVal = $hasFail ? '불합격' : ($allPass ? '합격' : ''); + } + } @endphp @if($judgementVal) @@ -203,7 +349,9 @@ class="doc-th" @php - $remarkVal = $document->data->where('field_key', 'footer_remark')->first()?->field_value ?? ''; + $remarkVal = $document->data->where('field_key', 'remark')->first()?->field_value + ?? $document->data->where('field_key', 'footer_remark')->first()?->field_value + ?? ''; @endphp @if($remarkVal) diff --git a/resources/views/documents/show.blade.php b/resources/views/documents/show.blade.php index 246c57cd..e8fa3400 100644 --- a/resources/views/documents/show.blade.php +++ b/resources/views/documents/show.blade.php @@ -134,11 +134,82 @@ class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-4 py-2 rounded-lg transiti

{{ $section->title }}

@if($section->image_path) - {{ $section->title }} + @php + $sectionImgUrl = preg_match('/^\d+\//', $section->image_path) + ? rtrim(config('app.api_url', 'http://api.sam.kr'), '/') . '/storage/tenants/' . $section->image_path + : asset('storage/' . $section->image_path); + @endphp + {{ $section->title }} @endif {{-- 검사 데이터 테이블 (읽기 전용) --}} + {{-- 정규화 형식: section_id + column_id + row_index + field_key 기반 조회 --}} @if($section->items->count() > 0 && $document->template->columns->count() > 0) + @php + // 데이터 조회 헬퍼: 정규화 형식 우선, 레거시 fallback + $getData = function($sectionId, $colId, $rowIdx, $fieldKey) use ($document) { + // 1차: 정규화 형식 (section_id + column_id + row_index + field_key) + $record = $document->data + ->where('section_id', $sectionId) + ->where('column_id', $colId) + ->where('row_index', $rowIdx) + ->where('field_key', $fieldKey) + ->first(); + return $record?->field_value ?? ''; + }; + + // 레거시 데이터 조회 헬퍼 (수입검사 호환: {itemId}_n{n}, {itemId}_result 등) + $getLegacyData = function($itemId, $fieldKey) use ($document) { + return $document->data->where('field_key', "{$itemId}_{$fieldKey}")->first()?->field_value + ?? $document->data->where('field_key', $fieldKey)->first()?->field_value + ?? ''; + }; + + // 컬럼 → 섹션 아이템 매핑 (React normalizeLabel 로직 동기화) + $normalizeLabel = fn($label) => preg_replace('/[①②③④⑤⑥⑦⑧⑨⑩\s]/u', '', trim($label)); + $allItems = $section->items; + $columnItemMap = []; + foreach ($document->template->columns as $col) { + $colKey = $normalizeLabel($col->label); + foreach ($allItems as $sItem) { + $itemKey = $normalizeLabel($sItem->item ?? $sItem->category ?? ''); + if ($itemKey === $colKey) { + $columnItemMap[$col->id] = $sItem; + break; + } + } + } + + // 기준치 해석: reference_attribute → work_order_item 치수 + $resolveStandard = function($colId, $rowIndex) use ($columnItemMap, &$workOrderItems) { + $sItem = $columnItemMap[$colId] ?? null; + if (!$sItem) return ''; + $woItem = $workOrderItems[$rowIndex] ?? null; + // 1. reference_attribute → work_order_item 치수 + if ($woItem) { + $fv = $sItem->field_values; + $refAttr = is_array($fv) ? ($fv['reference_attribute'] ?? null) : null; + if ($refAttr) { + $dimKey = $refAttr === 'length' ? 'width' : $refAttr; + $dimVal = $woItem->options[$dimKey] ?? null; + if ($dimVal) return (string) $dimVal; + } + } + // 2. standard_criteria + $sc = $sItem->standard_criteria; + if ($sc) { + if (is_array($sc)) { + if (isset($sc['nominal'])) return (string) $sc['nominal']; + if (isset($sc['min'], $sc['max'])) return $sc['min'] . ' ~ ' . $sc['max']; + if (isset($sc['max'])) return '≤ ' . $sc['max']; + if (isset($sc['min'])) return '≥ ' . $sc['min']; + } + return (string) $sc; + } + // 3. standard 텍스트 + return $sItem->standard ?? ''; + }; + @endphp
{{-- 테이블 헤더 --}} @@ -175,49 +246,129 @@ class="px-2 py-2 text-center text-xs font-medium text-gray-600 uppercase border @endif - {{-- 테이블 바디 (읽기 전용) --}} - {{-- React field_key 형식: {item_id}_n{n}, {item_id}_okng_n{n}, {item_id}_result --}} - @foreach($section->items as $rowIndex => $item) @php - $isOkng = $item->measurement_type === 'checkbox'; + // 행 수 결정: workOrderItems 기반 (React effectiveWorkItems와 동일) + // fallback: document_data의 max row_index + 1 + $rowCount = $workOrderItems->isNotEmpty() + ? $workOrderItems->count() + : max(1, ($document->data->where('section_id', $section->id)->max('row_index') ?? 0) + 1); @endphp + @for($rowIndex = 0; $rowIndex < $rowCount; $rowIndex++) @foreach($document->template->columns as $col) @if($col->column_type === 'complex' && $col->sub_labels) - {{-- complex: 측정치 (n1, n2, n3...) --}} + {{-- complex: sub_label 유형별 분리 (React inputIdx 로직 동기화) --}} + @php + $inputIdx = 0; + $mappedItem = $columnItemMap[$col->id] ?? null; + $isOkng = $mappedItem?->measurement_type === 'checkbox'; + @endphp @foreach($col->sub_labels as $subIndex => $subLabel) @php - $n = $subIndex + 1; - $fieldKey = $isOkng - ? "{$item->id}_okng_n{$n}" - : "{$item->id}_n{$n}"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $sl = strtolower($subLabel); + $isStandardSub = str_contains($sl, '도면') || str_contains($sl, '기준'); + $isOkNgSub = str_contains($sl, 'ok') || str_contains($sl, 'ng'); @endphp - + + @if($isStandardSub) + {{-- 기준치: document_data → work_order_item 치수 → item standard --}} + @php + $standardVal = $getData($section->id, $col->id, $rowIndex, 'standard'); + if (!$standardVal) $standardVal = $resolveStandard($col->id, $rowIndex); + @endphp + + @elseif($isOkNgSub) + {{-- OK·NG sub_label --}} + @php + $n = $inputIdx + 1; + $okVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ok"); + $ngVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ng"); + $savedVal = $okVal === 'OK' ? 'OK' : ($ngVal === 'NG' ? 'NG' : ''); + if (!$savedVal) { + $valFallback = $getData($section->id, $col->id, $rowIndex, 'value'); + if (in_array(strtolower($valFallback), ['ok', 'pass', '적합', '합격'])) $savedVal = 'OK'; + elseif (in_array(strtolower($valFallback), ['ng', 'fail', '부적합'])) $savedVal = 'NG'; + } + $inputIdx++; + @endphp + + @else + {{-- 측정값 sub_label --}} + @php + $n = $inputIdx + 1; + if ($isOkng) { + $okVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ok"); + $ngVal = $getData($section->id, $col->id, $rowIndex, "n{$n}_ng"); + $savedVal = $okVal === 'OK' ? 'OK' : ($ngVal === 'NG' ? 'NG' : ''); + if (!$savedVal) { + $valFallback = $getData($section->id, $col->id, $rowIndex, 'value'); + if (in_array(strtolower($valFallback), ['ok', 'pass', '적합', '합격'])) $savedVal = 'OK'; + elseif (in_array(strtolower($valFallback), ['ng', 'fail', '부적합'])) $savedVal = 'NG'; + } + } else { + $savedVal = $getData($section->id, $col->id, $rowIndex, "n{$n}"); + if (!$savedVal) $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + } + $inputIdx++; + @endphp + + @endif @endforeach @elseif($col->column_type === 'select') - {{-- select: 항목별 판정 → {item_id}_result --}} + {{-- select: 판정 --}} @php - $fieldKey = "{$item->id}_result"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + if (!$savedVal) { + $rowJudgment = $document->data->where('field_key', 'row_judgment')->first()?->field_value ?? ''; + if (in_array(strtolower($rowJudgment), ['pass', 'ok', '적합'])) $savedVal = 'OK'; + elseif (in_array(strtolower($rowJudgment), ['fail', 'ng', '부적합'])) $savedVal = 'NG'; + } @endphp @elseif($col->column_type === 'check') - {{-- check: 체크 결과 → {item_id}_result --}} + {{-- check: 체크 결과 --}} @php - $fieldKey = "{$item->id}_result"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); @endphp @elseif($col->column_type === 'measurement') - {{-- measurement: 수치 데이터 → {item_id}_n1 --}} + {{-- measurement: 수치 데이터 --}} @php - $fieldKey = "{$item->id}_n1"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'n1'); + if (!$savedVal) $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); @endphp @else - {{-- text: 정적 데이터 또는 입력된 텍스트 --}} + {{-- text: 일련번호 / 판정 / 기타 --}} @php - $staticValue = match(true) { - str_contains(strtolower($col->label), 'no') && strlen($col->label) <= 4 => $rowIndex + 1, - in_array($col->label, ['검사항목', '항목']) => $item->getFieldValue('item'), - in_array($col->label, ['검사기준', '기준']) => $item->getFieldValue('standard'), - in_array($col->label, ['검사방식', '방식', '검사방법']) => $item->getFieldValue('method'), - in_array($col->label, ['검사주기', '주기']) => $item->getFieldValue('frequency'), - in_array($col->label, ['규격', '적용규격', '관련규정']) => $item->getFieldValue('regulation'), - in_array($col->label, ['분류', '카테고리']) => $item->getFieldValue('category'), - default => null, - }; + $label = trim($col->label); + $isNoCol = (str_contains(strtolower($label), 'no') && strlen($label) <= 4) + || in_array($label, ['일렬번호', '일련번호', '번호', '순번']); + $isJudgeCol = str_contains($label, '판정'); @endphp - @if($staticValue !== null) - + @elseif($isJudgeCol) + @php + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + if (!$savedVal) { + $rowJudgment = $document->data->where('field_key', 'row_judgment')->first()?->field_value ?? ''; + if (in_array(strtolower($rowJudgment), ['pass', 'ok', '적합'])) $savedVal = 'OK'; + elseif (in_array(strtolower($rowJudgment), ['fail', 'ng', '부적합'])) $savedVal = 'NG'; + } + @endphp + @else @php - $fieldKey = "{$item->id}_n1"; - $savedVal = $document->data->where('field_key', $fieldKey)->first()?->field_value ?? ''; + $savedVal = $getData($section->id, $col->id, $rowIndex, 'value'); + if (!$savedVal) $savedVal = $getData($section->id, $col->id, $rowIndex, 'n1'); @endphp @endif @endif @endforeach - @endforeach + @endfor
- @if($isOkng && $savedVal) - - {{ strtoupper($savedVal) }} - - @else - {{ $savedVal ?: '-' }} - @endif - + {{ $standardVal ?: '-' }} + + @if($savedVal) + @if(strtolower($savedVal) === 'ok') + + + OK + + @else + + + NG + + @endif + @else + - + @endif + + @if($isOkng && $savedVal) + @if(strtolower($savedVal) === 'ok') + + + OK + + @else + + + NG + + @endif + @else + {{ $savedVal ?: '-' }} + @endif + @if($savedVal) - @php - $isPass = in_array(strtolower($savedVal), ['ok', '적합', '합격', 'pass']); - @endphp - + @php $isPass = in_array(strtolower($savedVal), ['ok', '적합', '합격', 'pass', '적']); @endphp + + @if($isPass) + + @else + + @endif {{ $isPass ? '적합' : '부적합' }} @else @@ -225,60 +376,81 @@ class="px-2 py-2 text-center text-xs font-medium text-gray-600 uppercase border @endif @if(in_array(strtolower($savedVal), ['ok', 'pass', '적합', '합격'])) - - - + + + + + @elseif($savedVal) - - - + + + + + @else - @endif {{ $savedVal ?: '-' }} - {{ $staticValue }} + @if($isNoCol) + {{ $rowIndex + 1 }} + @if(in_array(strtolower($savedVal ?? ''), ['ok', 'pass', '적합', '합격'])) + + + + + + @elseif($savedVal) + + + + + + @else + - + @endif {{ $savedVal ?: '-' }}
@@ -294,6 +466,15 @@ class="px-2 py-2 text-center text-xs font-medium text-gray-600 uppercase border $judgementVal = $document->data->where('field_key', 'overall_result')->first()?->field_value ?? $document->data->where('field_key', 'footer_judgement')->first()?->field_value ?? ''; + // fallback: overall_result 없으면 row_judgment에서 계산 (React calculateOverallResult 동일 로직) + if (!$judgementVal) { + $rowJudgments = $document->data->where('field_key', 'row_judgment')->pluck('field_value'); + if ($rowJudgments->isNotEmpty()) { + $hasFail = $rowJudgments->contains(fn($v) => in_array(strtolower($v), ['fail', '부', '부적합', '불합격'])); + $allPass = $rowJudgments->every(fn($v) => in_array(strtolower($v), ['pass', '적', '적합', '합격'])); + $judgementVal = $hasFail ? '불합격' : ($allPass ? '합격' : ''); + } + } $isPass = in_array(strtolower($judgementVal), ['pass', 'ok', '적합', '합격']); @endphp