withCount(['sections', 'columns']); // 검색 if ($search = $request->input('search')) { $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('title', 'like', "%{$search}%") ->orWhere('category', 'like', "%{$search}%"); }); } // 카테고리 필터 if ($category = $request->input('category')) { $query->where('category', $category); } // 활성 상태 필터 if ($request->has('is_active') && $request->input('is_active') !== '') { $query->where('is_active', $request->boolean('is_active')); } $templates = $query->orderBy('updated_at', 'desc') ->paginate($request->input('per_page', 10)); return view('document-templates.partials.table', compact('templates')); } /** * 단일 조회 */ public function show(int $id): JsonResponse { $template = DocumentTemplate::with([ 'approvalLines', 'basicFields', 'sections.items', 'columns', ])->findOrFail($id); return response()->json([ 'success' => true, 'data' => $template, ]); } /** * 생성 */ public function store(Request $request): JsonResponse { $validated = $request->validate([ 'name' => 'required|string|max:100', 'category' => 'nullable|string|max:50', 'title' => 'nullable|string|max:200', 'company_name' => 'nullable|string|max:100', 'company_address' => 'nullable|string|max:255', 'company_contact' => 'nullable|string|max:100', 'footer_remark_label' => 'nullable|string|max:50', 'footer_judgement_label' => 'nullable|string|max:50', 'footer_judgement_options' => 'nullable|array', 'is_active' => 'boolean', // 관계 데이터 'approval_lines' => 'nullable|array', 'basic_fields' => 'nullable|array', 'sections' => 'nullable|array', 'columns' => 'nullable|array', ]); try { DB::beginTransaction(); $template = DocumentTemplate::create([ 'tenant_id' => session('selected_tenant_id'), 'name' => $validated['name'], 'category' => $validated['category'] ?? null, 'title' => $validated['title'] ?? null, 'company_name' => $validated['company_name'] ?? '경동기업', 'company_address' => $validated['company_address'] ?? null, 'company_contact' => $validated['company_contact'] ?? null, 'footer_remark_label' => $validated['footer_remark_label'] ?? '부적합 내용', 'footer_judgement_label' => $validated['footer_judgement_label'] ?? '종합판정', 'footer_judgement_options' => $validated['footer_judgement_options'] ?? ['적합', '부적합'], 'is_active' => $validated['is_active'] ?? true, ]); // 관계 데이터 저장 $this->saveRelations($template, $validated); DB::commit(); return response()->json([ 'success' => true, 'message' => '문서양식이 생성되었습니다.', 'data' => $template->load(['approvalLines', 'basicFields', 'sections.items', 'columns']), ]); } catch (\Exception $e) { DB::rollBack(); return response()->json([ 'success' => false, 'message' => '생성 중 오류가 발생했습니다: '.$e->getMessage(), ], 500); } } /** * 수정 */ public function update(Request $request, int $id): JsonResponse { $template = DocumentTemplate::findOrFail($id); $validated = $request->validate([ 'name' => 'required|string|max:100', 'category' => 'nullable|string|max:50', 'title' => 'nullable|string|max:200', 'company_name' => 'nullable|string|max:100', 'company_address' => 'nullable|string|max:255', 'company_contact' => 'nullable|string|max:100', 'footer_remark_label' => 'nullable|string|max:50', 'footer_judgement_label' => 'nullable|string|max:50', 'footer_judgement_options' => 'nullable|array', 'is_active' => 'boolean', // 관계 데이터 'approval_lines' => 'nullable|array', 'basic_fields' => 'nullable|array', 'sections' => 'nullable|array', 'columns' => 'nullable|array', ]); try { DB::beginTransaction(); $template->update([ 'name' => $validated['name'], 'category' => $validated['category'] ?? null, 'title' => $validated['title'] ?? null, 'company_name' => $validated['company_name'] ?? null, 'company_address' => $validated['company_address'] ?? null, 'company_contact' => $validated['company_contact'] ?? null, 'footer_remark_label' => $validated['footer_remark_label'] ?? '부적합 내용', 'footer_judgement_label' => $validated['footer_judgement_label'] ?? '종합판정', 'footer_judgement_options' => $validated['footer_judgement_options'] ?? ['적합', '부적합'], 'is_active' => $validated['is_active'] ?? true, ]); // 관계 데이터 저장 (기존 데이터 삭제 후 재생성) $this->saveRelations($template, $validated, true); DB::commit(); return response()->json([ 'success' => true, 'message' => '문서양식이 수정되었습니다.', 'data' => $template->fresh(['approvalLines', 'basicFields', 'sections.items', 'columns']), ]); } catch (\Exception $e) { DB::rollBack(); return response()->json([ 'success' => false, 'message' => '수정 중 오류가 발생했습니다: '.$e->getMessage(), ], 500); } } /** * 삭제 */ public function destroy(int $id): JsonResponse { $template = DocumentTemplate::findOrFail($id); $template->delete(); return response()->json([ 'success' => true, 'message' => '문서양식이 삭제되었습니다.', ]); } /** * 활성 상태 토글 */ public function toggleActive(int $id): JsonResponse { $template = DocumentTemplate::findOrFail($id); $template->update(['is_active' => ! $template->is_active]); return response()->json([ 'success' => true, 'message' => $template->is_active ? '활성화되었습니다.' : '비활성화되었습니다.', 'is_active' => $template->is_active, ]); } /** * 이미지 업로드 */ public function uploadImage(Request $request): JsonResponse { $request->validate([ 'image' => 'required|image|max:5120', // 5MB ]); $path = $request->file('image')->store('document-templates', 'public'); return response()->json([ 'success' => true, 'path' => $path, 'url' => asset('storage/'.$path), ]); } /** * 관계 데이터 저장 */ private function saveRelations(DocumentTemplate $template, array $data, bool $deleteExisting = false): void { // 기존 데이터 삭제 (수정 시) if ($deleteExisting) { $template->approvalLines()->delete(); $template->basicFields()->delete(); // sections는 cascade로 items도 함께 삭제됨 $template->sections()->delete(); $template->columns()->delete(); } // 결재라인 if (! empty($data['approval_lines'])) { foreach ($data['approval_lines'] as $index => $line) { DocumentTemplateApprovalLine::create([ 'template_id' => $template->id, 'name' => $line['name'] ?? '', 'dept' => $line['dept'] ?? '', 'role' => $line['role'] ?? '', 'sort_order' => $index, ]); } } // 기본 필드 if (! empty($data['basic_fields'])) { foreach ($data['basic_fields'] as $index => $field) { DocumentTemplateBasicField::create([ 'template_id' => $template->id, 'label' => $field['label'] ?? '', 'field_type' => $field['field_type'] ?? 'text', 'default_value' => $field['default_value'] ?? '', 'sort_order' => $index, ]); } } // 섹션 및 항목 if (! empty($data['sections'])) { foreach ($data['sections'] as $sIndex => $section) { $newSection = DocumentTemplateSection::create([ 'template_id' => $template->id, 'title' => $section['title'] ?? '', 'image_path' => $section['image_path'] ?? null, 'sort_order' => $sIndex, ]); if (! empty($section['items'])) { foreach ($section['items'] as $iIndex => $item) { DocumentTemplateSectionItem::create([ 'section_id' => $newSection->id, 'category' => $item['category'] ?? '', 'item' => $item['item'] ?? '', 'standard' => $item['standard'] ?? '', 'method' => $item['method'] ?? '', 'frequency' => $item['frequency'] ?? '', 'regulation' => $item['regulation'] ?? '', 'sort_order' => $iIndex, ]); } } } } // 컬럼 if (! empty($data['columns'])) { foreach ($data['columns'] as $index => $column) { DocumentTemplateColumn::create([ 'template_id' => $template->id, 'label' => $column['label'] ?? '', 'width' => $column['width'] ?? '100px', 'column_type' => $column['column_type'] ?? 'text', 'group_name' => $column['group_name'] ?? null, 'sub_labels' => $column['sub_labels'] ?? null, 'sort_order' => $index, ]); } } } }