Files
sam-manage/resources/views/documents/edit.blade.php
권혁성 c65d3f49dc feat: 문서 관리 시스템 MNG 관리자 패널 구현 (Phase 2)
- Document 관련 모델 4개 생성 (Document, DocumentApproval, DocumentData, DocumentAttachment)
- DocumentController 생성 (목록/생성/상세/수정 페이지)
- DocumentApiController 생성 (AJAX CRUD 처리)
- 문서 관리 뷰 3개 생성 (index, edit, show)
- 웹/API 라우트 등록

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 21:51:23 +09:00

211 lines
10 KiB
PHP

@extends('layouts.app')
@section('title', $isCreate ? '새 문서 작성' : '문서 수정')
@section('content')
<div class="p-6">
{{-- 헤더 --}}
<div class="flex justify-between items-center mb-6">
<div>
<h1 class="text-2xl font-bold text-gray-800">{{ $isCreate ? '새 문서 작성' : '문서 수정' }}</h1>
<p class="text-sm text-gray-500 mt-1">
@if($document)
{{ $document->document_no }} - {{ $document->title }}
@else
템플릿을 선택하여 문서를 작성합니다.
@endif
</p>
</div>
<a href="{{ route('documents.index') }}"
class="inline-flex items-center px-4 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded-lg hover:bg-gray-200 transition-colors">
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18"/>
</svg>
목록으로
</a>
</div>
{{-- 템플릿 선택 (생성 ) --}}
@if($isCreate && !$template)
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-6">
<h2 class="text-lg font-semibold text-gray-800 mb-4">템플릿 선택</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
@forelse($templates as $tpl)
<a href="{{ route('documents.create', ['template_id' => $tpl->id]) }}"
class="block p-4 border border-gray-200 rounded-lg hover:border-blue-500 hover:bg-blue-50 transition-colors">
<h3 class="font-medium text-gray-900">{{ $tpl->name }}</h3>
<p class="text-sm text-gray-500 mt-1">{{ $tpl->category }}</p>
</a>
@empty
<p class="text-gray-500 col-span-3">사용 가능한 템플릿이 없습니다.</p>
@endforelse
</div>
</div>
@endif
{{-- 문서 --}}
@if($template)
<form id="documentForm" class="space-y-6">
@csrf
<input type="hidden" name="template_id" value="{{ $template->id }}">
{{-- 기본 정보 --}}
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h2 class="text-lg font-semibold text-gray-800 mb-4">기본 정보</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">템플릿</label>
<input type="text" value="{{ $template->name }}" disabled
class="w-full rounded-lg border-gray-300 bg-gray-50 text-sm">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
제목 <span class="text-red-500">*</span>
</label>
<input type="text" name="title" value="{{ $document->title ?? '' }}" required
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500"
placeholder="문서 제목을 입력하세요">
</div>
</div>
</div>
{{-- 기본 필드 --}}
@if($template->basicFields && $template->basicFields->count() > 0)
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h2 class="text-lg font-semibold text-gray-800 mb-4">{{ $template->title ?? '문서 정보' }}</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
@foreach($template->basicFields as $field)
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">
{{ $field->label }}
@if($field->is_required)
<span class="text-red-500">*</span>
@endif
</label>
@if($field->type === 'textarea')
<textarea name="data[{{ $field->field_key }}]"
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500"
rows="3"
{{ $field->is_required ? 'required' : '' }}
placeholder="{{ $field->placeholder ?? '' }}">{{ $document?->data->where('field_key', $field->field_key)->first()?->field_value ?? '' }}</textarea>
@elseif($field->type === 'select' && $field->options)
<select name="data[{{ $field->field_key }}]"
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500"
{{ $field->is_required ? 'required' : '' }}>
<option value="">선택하세요</option>
@foreach($field->options as $option)
<option value="{{ $option }}" {{ ($document?->data->where('field_key', $field->field_key)->first()?->field_value ?? '') === $option ? 'selected' : '' }}>
{{ $option }}
</option>
@endforeach
</select>
@elseif($field->type === 'date')
<input type="date" name="data[{{ $field->field_key }}]"
value="{{ $document?->data->where('field_key', $field->field_key)->first()?->field_value ?? '' }}"
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500"
{{ $field->is_required ? 'required' : '' }}>
@elseif($field->type === 'number')
<input type="number" name="data[{{ $field->field_key }}]"
value="{{ $document?->data->where('field_key', $field->field_key)->first()?->field_value ?? '' }}"
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500"
{{ $field->is_required ? 'required' : '' }}
placeholder="{{ $field->placeholder ?? '' }}">
@else
<input type="text" name="data[{{ $field->field_key }}]"
value="{{ $document?->data->where('field_key', $field->field_key)->first()?->field_value ?? '' }}"
class="w-full rounded-lg border-gray-300 text-sm focus:border-blue-500 focus:ring-blue-500"
{{ $field->is_required ? 'required' : '' }}
placeholder="{{ $field->placeholder ?? '' }}">
@endif
</div>
@endforeach
</div>
</div>
@endif
{{-- 섹션 (테이블 형태) --}}
@if($template->sections && $template->sections->count() > 0)
@foreach($template->sections as $section)
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<h2 class="text-lg font-semibold text-gray-800 mb-4">{{ $section->name }}</h2>
<p class="text-sm text-gray-500 mb-4">테이블 형태의 데이터는 추후 구현 예정입니다.</p>
</div>
@endforeach
@endif
{{-- 버튼 --}}
<div class="flex justify-end gap-3">
<a href="{{ route('documents.index') }}"
class="px-6 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded-lg hover:bg-gray-200 transition-colors">
취소
</a>
<button type="submit"
class="px-6 py-2 bg-blue-600 text-white text-sm font-medium rounded-lg hover:bg-blue-700 transition-colors">
{{ $isCreate ? '저장' : '수정' }}
</button>
</div>
</form>
@endif
</div>
@endsection
@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('documentForm');
if (!form) return;
form.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(form);
const data = {
template_id: formData.get('template_id'),
title: formData.get('title'),
data: []
};
// data 필드 수집
for (const [key, value] of formData.entries()) {
if (key.startsWith('data[') && key.endsWith(']')) {
const fieldKey = key.slice(5, -1);
data.data.push({
field_key: fieldKey,
field_value: value
});
}
}
const isCreate = {{ $isCreate ? 'true' : 'false' }};
const url = isCreate ? '/api/admin/documents' : '/api/admin/documents/{{ $document?->id }}';
const method = isCreate ? 'POST' : 'PATCH';
fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => {
if (result.success) {
alert(isCreate ? '문서가 저장되었습니다.' : '문서가 수정되었습니다.');
window.location.href = '/documents';
} else {
alert(result.message || '오류가 발생했습니다.');
}
})
.catch(error => {
console.error('Error:', error);
alert('오류가 발생했습니다.');
});
});
});
</script>
@endpush