feat:검사 기준서 동적화 + 소스 테이블 통합 검색
- 동적 필드/연결 모델 추가 (SectionField, Link, LinkValue, Preset) - 통합 검색 API (SourceTableSearchController) - items/processes/lots/users - 템플릿 편집 UI: 소스 테이블 드롭다운 + datalist 검색/선택 - 문서 작성/인쇄/상세 뷰: getFieldValue() 기반 동적 렌더링 - DocumentTemplateApiController: source_table 기반 저장/복제 - DocumentController: sectionFields/links eager loading 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,10 @@
|
||||
use App\Models\DocumentTemplateApprovalLine;
|
||||
use App\Models\DocumentTemplateBasicField;
|
||||
use App\Models\DocumentTemplateColumn;
|
||||
use App\Models\DocumentTemplateLink;
|
||||
use App\Models\DocumentTemplateLinkValue;
|
||||
use App\Models\DocumentTemplateSection;
|
||||
use App\Models\DocumentTemplateSectionField;
|
||||
use App\Models\DocumentTemplateSectionItem;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -71,6 +74,8 @@ public function show(int $id): JsonResponse
|
||||
'basicFields',
|
||||
'sections.items',
|
||||
'columns',
|
||||
'sectionFields',
|
||||
'links.linkValues',
|
||||
])->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
@@ -103,6 +108,8 @@ public function store(Request $request): JsonResponse
|
||||
'basic_fields' => 'nullable|array',
|
||||
'sections' => 'nullable|array',
|
||||
'columns' => 'nullable|array',
|
||||
'section_fields' => 'nullable|array',
|
||||
'template_links' => 'nullable|array',
|
||||
]);
|
||||
|
||||
try {
|
||||
@@ -132,7 +139,7 @@ public function store(Request $request): JsonResponse
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '문서양식이 생성되었습니다.',
|
||||
'data' => $template->load(['approvalLines', 'basicFields', 'sections.items', 'columns']),
|
||||
'data' => $template->load(['approvalLines', 'basicFields', 'sections.items', 'columns', 'sectionFields', 'links.linkValues']),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
@@ -170,6 +177,8 @@ public function update(Request $request, int $id): JsonResponse
|
||||
'basic_fields' => 'nullable|array',
|
||||
'sections' => 'nullable|array',
|
||||
'columns' => 'nullable|array',
|
||||
'section_fields' => 'nullable|array',
|
||||
'template_links' => 'nullable|array',
|
||||
]);
|
||||
|
||||
try {
|
||||
@@ -198,7 +207,7 @@ public function update(Request $request, int $id): JsonResponse
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => '문서양식이 수정되었습니다.',
|
||||
'data' => $template->fresh(['approvalLines', 'basicFields', 'sections.items', 'columns']),
|
||||
'data' => $template->fresh(['approvalLines', 'basicFields', 'sections.items', 'columns', 'sectionFields', 'links.linkValues']),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
@@ -262,6 +271,8 @@ public function forceDestroy(int $id): JsonResponse
|
||||
$section->delete();
|
||||
});
|
||||
$template->columns()->delete();
|
||||
$template->sectionFields()->delete();
|
||||
$template->links()->delete(); // cascade로 linkValues도 삭제
|
||||
$template->forceDelete();
|
||||
|
||||
return response()->json([
|
||||
@@ -321,6 +332,8 @@ public function duplicate(Request $request, int $id): JsonResponse
|
||||
'basicFields',
|
||||
'sections.items',
|
||||
'columns',
|
||||
'sectionFields',
|
||||
'links.linkValues',
|
||||
])->findOrFail($id);
|
||||
|
||||
$newName = $request->input('name', $source->name.' (복사)');
|
||||
@@ -404,6 +417,45 @@ public function duplicate(Request $request, int $id): JsonResponse
|
||||
]);
|
||||
}
|
||||
|
||||
// 검사 기준서 동적 필드 복제
|
||||
foreach ($source->sectionFields as $field) {
|
||||
DocumentTemplateSectionField::create([
|
||||
'template_id' => $newTemplate->id,
|
||||
'field_key' => $field->field_key,
|
||||
'label' => $field->label,
|
||||
'field_type' => $field->field_type,
|
||||
'options' => $field->options,
|
||||
'width' => $field->width,
|
||||
'is_required' => $field->is_required,
|
||||
'sort_order' => $field->sort_order,
|
||||
]);
|
||||
}
|
||||
|
||||
// 외부 키 매핑 복제
|
||||
foreach ($source->links as $link) {
|
||||
$newLink = DocumentTemplateLink::create([
|
||||
'template_id' => $newTemplate->id,
|
||||
'link_key' => $link->link_key,
|
||||
'label' => $link->label,
|
||||
'link_type' => $link->link_type,
|
||||
'source_table' => $link->source_table,
|
||||
'search_params' => $link->search_params,
|
||||
'display_fields' => $link->display_fields,
|
||||
'is_required' => $link->is_required,
|
||||
'sort_order' => $link->sort_order,
|
||||
]);
|
||||
|
||||
foreach ($link->linkValues as $value) {
|
||||
DocumentTemplateLinkValue::create([
|
||||
'template_id' => $newTemplate->id,
|
||||
'link_id' => $newLink->id,
|
||||
'linkable_id' => $value->linkable_id,
|
||||
'sort_order' => $value->sort_order,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
@@ -476,6 +528,9 @@ private function saveRelations(DocumentTemplate $template, array $data, bool $de
|
||||
// sections는 cascade로 items도 함께 삭제됨
|
||||
$template->sections()->delete();
|
||||
$template->columns()->delete();
|
||||
$template->sectionFields()->delete();
|
||||
// links는 cascade로 linkValues도 함께 삭제됨
|
||||
$template->links()->delete();
|
||||
}
|
||||
|
||||
// 결재라인
|
||||
@@ -551,5 +606,51 @@ private function saveRelations(DocumentTemplate $template, array $data, bool $de
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 검사 기준서 동적 필드 정의
|
||||
if (! empty($data['section_fields'])) {
|
||||
foreach ($data['section_fields'] as $index => $field) {
|
||||
DocumentTemplateSectionField::create([
|
||||
'template_id' => $template->id,
|
||||
'field_key' => $field['field_key'] ?? '',
|
||||
'label' => $field['label'] ?? '',
|
||||
'field_type' => $field['field_type'] ?? 'text',
|
||||
'options' => $field['options'] ?? null,
|
||||
'width' => $field['width'] ?? '100px',
|
||||
'is_required' => $field['is_required'] ?? false,
|
||||
'sort_order' => $index,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// 외부 키 매핑 + 연결 값
|
||||
if (! empty($data['template_links'])) {
|
||||
foreach ($data['template_links'] as $index => $link) {
|
||||
$newLink = DocumentTemplateLink::create([
|
||||
'template_id' => $template->id,
|
||||
'link_key' => $link['link_key'] ?? '',
|
||||
'label' => $link['label'] ?? '',
|
||||
'link_type' => $link['link_type'] ?? 'single',
|
||||
'source_table' => $link['source_table'] ?? '',
|
||||
'search_params' => $link['search_params'] ?? null,
|
||||
'display_fields' => $link['display_fields'] ?? null,
|
||||
'is_required' => $link['is_required'] ?? false,
|
||||
'sort_order' => $index,
|
||||
]);
|
||||
|
||||
// 연결 값 저장
|
||||
if (! empty($link['values'])) {
|
||||
foreach ($link['values'] as $vIndex => $value) {
|
||||
DocumentTemplateLinkValue::create([
|
||||
'template_id' => $template->id,
|
||||
'link_id' => $newLink->id,
|
||||
'linkable_id' => $value['linkable_id'] ?? $value['id'] ?? $value,
|
||||
'sort_order' => $vIndex,
|
||||
'created_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user