feat:E-Sign 템플릿 관리 시스템 Phase 2 구현

- 템플릿 관리 전용 페이지 (카드 그리드, 검색/필터, 편집/복제/삭제)
- API: showTemplate, updateTemplate, duplicateTemplate 추가
- indexTemplates에 category/search 필터 추가
- 계약 생성 시 템플릿 선택 UI 추가
- 필드 에디터에서 URL 파라미터 template_id 자동 적용
- EsignFieldTemplate 모델에 category 필드 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-12 18:55:06 +09:00
parent 203d52300a
commit ec43fe1991
7 changed files with 598 additions and 5 deletions

View File

@@ -363,14 +363,19 @@ public function indexTemplates(Request $request): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
$query = EsignFieldTemplate::forTenant($tenantId)
->where('is_active', true)
->with('items');
->where('is_active', true);
if ($category = $request->input('category')) {
$query->where('category', $category);
}
if ($search = $request->input('search')) {
$query->where('name', 'like', "%{$search}%");
}
if ($signerCount = $request->input('signer_count')) {
$query->where('signer_count', $signerCount);
}
$templates = $query->orderBy('created_at', 'desc')->get();
$templates = $query->withCount('items')->with('creator:id,name')->latest()->get();
return response()->json(['success' => true, 'data' => $templates]);
}
@@ -383,6 +388,7 @@ public function storeTemplate(Request $request): JsonResponse
$request->validate([
'name' => 'required|string|max:100',
'description' => 'nullable|string',
'category' => 'nullable|string|max:50',
'items' => 'required|array|min:1',
'items.*.signer_order' => 'required|integer|min:1',
'items.*.page_number' => 'required|integer|min:1',
@@ -406,6 +412,7 @@ public function storeTemplate(Request $request): JsonResponse
'tenant_id' => $tenantId,
'name' => $request->input('name'),
'description' => $request->input('description'),
'category' => $request->input('category'),
'signer_count' => $signerCount,
'is_active' => true,
'created_by' => auth()->id(),
@@ -437,6 +444,95 @@ public function storeTemplate(Request $request): JsonResponse
]);
}
/**
* 템플릿 단건 조회
*/
public function showTemplate(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
$template = EsignFieldTemplate::forTenant($tenantId)
->where('is_active', true)
->with(['items', 'creator:id,name'])
->findOrFail($id);
return response()->json(['success' => true, 'data' => $template]);
}
/**
* 템플릿 메타데이터 수정
*/
public function updateTemplate(Request $request, int $id): JsonResponse
{
$request->validate([
'name' => 'required|string|max:100',
'description' => 'nullable|string',
'category' => 'nullable|string|max:50',
]);
$tenantId = session('selected_tenant_id', 1);
$template = EsignFieldTemplate::forTenant($tenantId)->findOrFail($id);
$template->update([
'name' => $request->input('name'),
'description' => $request->input('description'),
'category' => $request->input('category'),
]);
return response()->json([
'success' => true,
'message' => '템플릿이 수정되었습니다.',
'data' => $template->fresh()->load('creator:id,name'),
]);
}
/**
* 템플릿 복제
*/
public function duplicateTemplate(int $id): JsonResponse
{
$tenantId = session('selected_tenant_id', 1);
$template = EsignFieldTemplate::forTenant($tenantId)
->where('is_active', true)
->with('items')
->findOrFail($id);
$newTemplate = DB::transaction(function () use ($template, $tenantId) {
$newTemplate = EsignFieldTemplate::create([
'tenant_id' => $tenantId,
'name' => $template->name . ' (복사)',
'description' => $template->description,
'category' => $template->category,
'signer_count' => $template->signer_count,
'is_active' => true,
'created_by' => auth()->id(),
]);
foreach ($template->items as $item) {
EsignFieldTemplateItem::create([
'template_id' => $newTemplate->id,
'signer_order' => $item->signer_order,
'page_number' => $item->page_number,
'position_x' => $item->position_x,
'position_y' => $item->position_y,
'width' => $item->width,
'height' => $item->height,
'field_type' => $item->field_type,
'field_label' => $item->field_label,
'is_required' => $item->is_required,
'sort_order' => $item->sort_order,
]);
}
return $newTemplate;
});
return response()->json([
'success' => true,
'message' => '템플릿이 복제되었습니다.',
'data' => $newTemplate->load(['items', 'creator:id,name'])->loadCount('items'),
]);
}
/**
* 템플릿 삭제 (soft: is_active=false)
*/