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
-
 }})
+
@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
- |
- {{ $savedVal ?: '-' }}
- |
+
+ @if($isStandardSub)
+ @php
+ $standardVal = $getData($section->id, $col->id, $rowIndex, 'standard');
+ if (!$standardVal) $standardVal = $resolveStandard($col->id, $rowIndex);
+ @endphp
+
+ {{ $standardVal ?: '-' }}
+ |
+ @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
+
+ @if($savedVal)
+ {{ strtoupper($savedVal) }}
+ @else
+ -
+ @endif
+ |
+ @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
+
+ @if($isOkng && $savedVal)
+ {{ strtoupper($savedVal) }}
+ @else
+ {{ $savedVal ?: '-' }}
+ @endif
+ |
+ @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
@if($savedVal)
-
- {{ $savedVal }}
+
+ {{ in_array(strtolower($savedVal), ['ok', 'pass', '적합', '합격', '적']) ? '적합' : '부적합' }}
@else
-
@@ -120,51 +247,59 @@ class="doc-th"
|
@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
- @if($savedVal === 'OK')
- OK
+ @if(in_array(strtolower($savedVal), ['ok', 'pass', '적합', '합격']))
+ OK
+ @elseif($savedVal)
+ NG
@else
-
@endif
|
@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
{{ $savedVal ?: '-' }}
|
@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)
-
- {{ $staticValue }}
+ @if($isNoCol)
+ | {{ $rowIndex + 1 }} |
+ @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
+
+ @if(in_array(strtolower($savedVal ?? ''), ['ok', 'pass', '적합', '합격']))
+ OK
+ @elseif($savedVal)
+ NG
+ @else
+ -
+ @endif
|
@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
{{ $savedVal ?: '-' }}
@@ -173,7 +308,7 @@ class="doc-th"
@endif
@endforeach
|
- @endforeach
+ @endfor
@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)
-
 }})
+ @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
+

@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($isOkng && $savedVal)
-
- {{ strtoupper($savedVal) }}
-
- @else
- {{ $savedVal ?: '-' }}
- @endif
- |
+
+ @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
+
+ {{ $standardVal ?: '-' }}
+ |
+ @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
+
+ @if($savedVal)
+ @if(strtolower($savedVal) === 'ok')
+
+
+ OK
+
+ @else
+
+
+ NG
+
+ @endif
+ @else
+ -
+ @endif
+ |
+ @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
+
+ @if($isOkng && $savedVal)
+ @if(strtolower($savedVal) === 'ok')
+
+
+ OK
+
+ @else
+
+
+ NG
+
+ @endif
+ @else
+ {{ $savedVal ?: '-' }}
+ @endif
+ |
+ @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
@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
|
@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
@if(in_array(strtolower($savedVal), ['ok', 'pass', '적합', '합격']))
-
+
+
+
@elseif($savedVal)
-
+
+
+
@else
-
@endif
|
@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
{{ $savedVal ?: '-' }} |
@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)
-
- {{ $staticValue }}
+ @if($isNoCol)
+ | {{ $rowIndex + 1 }} |
+ @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
+
+ @if(in_array(strtolower($savedVal ?? ''), ['ok', 'pass', '적합', '합격']))
+
+
+
+ @elseif($savedVal)
+
+
+
+ @else
+ -
+ @endif
|
@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
{{ $savedVal ?: '-' }} |
@endif
@endif
@endforeach
- @endforeach
+ @endfor
@@ -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