feat:전자서명 문서 다운로드 시 미리보기 PDF 제공 (서명/도장 제외 필드 합성)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -388,9 +388,18 @@ public function downloadDocument(string $token): StreamedResponse|JsonResponse
|
||||
}
|
||||
|
||||
// 서명 완료된 PDF가 있으면 우선 제공
|
||||
$filePath = $contract->signed_file_path && Storage::disk('local')->exists($contract->signed_file_path)
|
||||
? $contract->signed_file_path
|
||||
: $contract->original_file_path;
|
||||
if ($contract->signed_file_path && Storage::disk('local')->exists($contract->signed_file_path)) {
|
||||
$filePath = $contract->signed_file_path;
|
||||
} else {
|
||||
// 서명 전: 텍스트/날짜/체크박스 필드가 합성된 미리보기 PDF 생성
|
||||
try {
|
||||
$pdfService = new PdfSignatureService();
|
||||
$filePath = $pdfService->generatePreview($contract);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('미리보기 PDF 생성 실패, 원본 제공', ['error' => $e->getMessage()]);
|
||||
$filePath = $contract->original_file_path;
|
||||
}
|
||||
}
|
||||
|
||||
if (! Storage::disk('local')->exists($filePath)) {
|
||||
return response()->json(['success' => false, 'message' => '문서 파일이 존재하지 않습니다.'], 404);
|
||||
|
||||
@@ -99,6 +99,63 @@ public function mergeSignatures(EsignContract $contract): string
|
||||
return $signedRelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 서명/도장을 제외한 필드(텍스트, 날짜, 체크박스)만 합성한 미리보기 PDF를 생성한다.
|
||||
* 서명 전 문서 확인 시 사용된다.
|
||||
*/
|
||||
public function generatePreview(EsignContract $contract): string
|
||||
{
|
||||
$disk = Storage::disk('local');
|
||||
$originalPath = $disk->path($contract->original_file_path);
|
||||
|
||||
if (! file_exists($originalPath)) {
|
||||
throw new \RuntimeException("원본 PDF 파일이 존재하지 않습니다: {$contract->original_file_path}");
|
||||
}
|
||||
|
||||
$pdf = new Fpdi();
|
||||
$pdf->setPrintHeader(false);
|
||||
$pdf->setPrintFooter(false);
|
||||
|
||||
$pageCount = $pdf->setSourceFile($originalPath);
|
||||
|
||||
// 서명/도장을 제외한 필드만 조회
|
||||
$signFields = EsignSignField::withoutGlobalScopes()
|
||||
->where('contract_id', $contract->id)
|
||||
->whereNotIn('field_type', ['signature', 'stamp'])
|
||||
->with('signer')
|
||||
->orderBy('page_number')
|
||||
->orderBy('sort_order')
|
||||
->get()
|
||||
->groupBy('page_number');
|
||||
|
||||
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
|
||||
$templateId = $pdf->importPage($pageNo);
|
||||
$size = $pdf->getTemplateSize($templateId);
|
||||
|
||||
$pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
|
||||
$pdf->useTemplate($templateId, 0, 0, $size['width'], $size['height']);
|
||||
|
||||
if ($signFields->has($pageNo)) {
|
||||
foreach ($signFields[$pageNo] as $field) {
|
||||
$this->overlayField($pdf, $field, $size['width'], $size['height']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 미리보기 PDF 저장
|
||||
$previewDir = "esign/{$contract->tenant_id}/preview";
|
||||
$previewRelPath = "{$previewDir}/{$contract->id}_preview.pdf";
|
||||
$previewAbsPath = $disk->path($previewRelPath);
|
||||
|
||||
if (! is_dir(dirname($previewAbsPath))) {
|
||||
mkdir(dirname($previewAbsPath), 0755, true);
|
||||
}
|
||||
|
||||
$pdf->Output($previewAbsPath, 'F');
|
||||
|
||||
return $previewRelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* 개별 필드를 PDF 위에 오버레이한다.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user