fix: [approvals] 재직증명서 레이아웃 개선 - A4 용지 내 수직 배분 조정

- HTML 미리보기: @page A4 설정, cert-page wrapper, padding/font-size 증가
- PDF(TCPDF): 상단여백 추가, 섹션간격 확대, rowHeight 8→10, 본문 10→11pt
- 증명문구/날짜 12→14pt, 회사명 14→16pt
- create/show 동일 적용
This commit is contained in:
김보곤
2026-03-06 10:25:55 +09:00
parent 71fce456b5
commit 4b478b4e05
3 changed files with 62 additions and 59 deletions

View File

@@ -76,21 +76,24 @@ public function generatePdfResponse(array $content): \Illuminate\Http\Response
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetMargins(20, 20, 20);
$pdf->SetMargins(20, 30, 20);
$pdf->SetAutoPageBreak(true, 20);
$font = $this->getKoreanFont();
$pdf->AddPage();
// 상단 여백
$pdf->Ln(10);
// 제목
$pdf->SetFont($font, 'B', 22);
$pdf->SetFont($font, 'B', 24);
$pdf->Cell(0, 20, '재 직 증 명 서', 0, 1, 'C');
$pdf->Ln(8);
$pdf->Ln(12);
// === 1. 인적사항 ===
$pdf->SetFont($font, 'B', 12);
$pdf->Cell(0, 8, '1. 인적사항', 0, 1, 'L');
$pdf->SetFont($font, 'B', 13);
$pdf->Cell(0, 10, '1. 인적사항', 0, 1, 'L');
$pdf->Ln(2);
$this->addTableRow($pdf, $font, [
@@ -100,11 +103,11 @@ public function generatePdfResponse(array $content): \Illuminate\Http\Response
$this->addTableRow($pdf, $font, [
['주 소', $content['address'] ?? '-', 0],
]);
$pdf->Ln(6);
$pdf->Ln(8);
// === 2. 재직사항 ===
$pdf->SetFont($font, 'B', 12);
$pdf->Cell(0, 8, '2. 재직사항', 0, 1, 'L');
$pdf->SetFont($font, 'B', 13);
$pdf->Cell(0, 10, '2. 재직사항', 0, 1, 'L');
$pdf->Ln(2);
$this->addTableRow($pdf, $font, [
@@ -123,34 +126,34 @@ public function generatePdfResponse(array $content): \Illuminate\Http\Response
$this->addTableRow($pdf, $font, [
['재직기간', $hireDateDisplay, 0],
]);
$pdf->Ln(6);
$pdf->Ln(8);
// === 3. 발급정보 ===
$pdf->SetFont($font, 'B', 12);
$pdf->Cell(0, 8, '3. 발급정보', 0, 1, 'L');
$pdf->SetFont($font, 'B', 13);
$pdf->Cell(0, 10, '3. 발급정보', 0, 1, 'L');
$pdf->Ln(2);
$this->addTableRow($pdf, $font, [
['사용용도', $content['purpose'] ?? '-', 0],
]);
$pdf->Ln(12);
$pdf->Ln(20);
// 증명 문구
$pdf->SetFont($font, '', 12);
$pdf->Cell(0, 10, '위 사항을 증명합니다.', 0, 1, 'C');
$pdf->Ln(6);
$pdf->SetFont($font, '', 14);
$pdf->Cell(0, 12, '위 사항을 증명합니다.', 0, 1, 'C');
$pdf->Ln(10);
// 발급일
$issueDate = $content['issue_date'] ?? date('Y-m-d');
$issueDateFormatted = $this->formatDate($issueDate);
$pdf->SetFont($font, 'B', 12);
$pdf->Cell(0, 10, $issueDateFormatted, 0, 1, 'C');
$pdf->Ln(12);
$pdf->SetFont($font, 'B', 14);
$pdf->Cell(0, 12, $issueDateFormatted, 0, 1, 'C');
$pdf->Ln(20);
// 회사명 + 대표이사
$ceoName = $content['ceo_name'] ?? '';
$pdf->SetFont($font, 'B', 14);
$pdf->Cell(0, 10, ($content['company_name'] ?? '').' 대표이사 '.$ceoName.' (인)', 0, 1, 'C');
$pdf->SetFont($font, 'B', 16);
$pdf->Cell(0, 12, ($content['company_name'] ?? '').' 대표이사 '.$ceoName.' (인)', 0, 1, 'C');
$pdfContent = $pdf->Output('', 'S');
$fileName = '재직증명서_'.($content['name'] ?? '').'.pdf';
@@ -167,24 +170,24 @@ public function generatePdfResponse(array $content): \Illuminate\Http\Response
private function addTableRow(\TCPDF $pdf, string $font, array $cells): void
{
$pageWidth = $pdf->getPageWidth() - 40; // margins
$rowHeight = 8;
$rowHeight = 10;
$thWidth = 30;
if (count($cells) === 1) {
// 단일 셀: th + td (전체 너비)
$pdf->SetFont($font, 'B', 10);
$pdf->SetFont($font, 'B', 11);
$pdf->SetFillColor(248, 249, 250);
$pdf->Cell($thWidth, $rowHeight, $cells[0][0], 1, 0, 'L', true);
$pdf->SetFont($font, '', 10);
$pdf->SetFont($font, '', 11);
$pdf->Cell($pageWidth - $thWidth, $rowHeight, $cells[0][1], 1, 1, 'L');
} else {
// 복수 셀: th+td + th+td
$tdWidth = ($pageWidth - $thWidth * 2) / 2;
foreach ($cells as $cell) {
$pdf->SetFont($font, 'B', 10);
$pdf->SetFont($font, 'B', 11);
$pdf->SetFillColor(248, 249, 250);
$pdf->Cell($thWidth, $rowHeight, $cell[0], 1, 0, 'L', true);
$pdf->SetFont($font, '', 10);
$pdf->SetFont($font, '', 11);
$pdf->Cell($tdWidth, $rowHeight, $cell[1], 1, 0, 'L');
}
$pdf->Ln();

View File

@@ -1017,10 +1017,10 @@ function printCertPreview() {
const content = document.getElementById('cert-preview-content').innerHTML;
const win = window.open('', '_blank', 'width=800,height=1000');
win.document.write('<html><head><title>재직증명서</title>');
win.document.write('<style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:48px 56px;margin:0;} table{border-collapse:collapse;width:100%;} th,td{border:1px solid #333;padding:10px 14px;font-size:14px;} th{background:#f8f9fa;font-weight:600;text-align:left;white-space:nowrap;width:120px;} @media print{body{padding:40px 48px;}}</style>');
win.document.write('</head><body>');
win.document.write('<style>@page{size:A4;margin:0;} body{font-family:"Pretendard","Malgun Gothic",sans-serif;margin:0;padding:0;} .cert-page{padding:80px 56px 60px;box-sizing:border-box;} table{border-collapse:collapse;width:100%;} th,td{border:1px solid #333;padding:14px 16px;font-size:15px;} th{background:#f8f9fa;font-weight:600;text-align:left;white-space:nowrap;width:130px;}</style>');
win.document.write('</head><body><div class="cert-page">');
win.document.write(content);
win.document.write('</body></html>');
win.document.write('</div></body></html>');
win.document.close();
win.onload = function() { win.print(); };
}
@@ -1486,14 +1486,14 @@ function buildResignationPreviewHtml(d) {
function buildCertPreviewHtml(d) {
const e = (s) => { const div = document.createElement('div'); div.textContent = s; return div.innerHTML; };
const thStyle = 'border:1px solid #333; padding:10px 14px; background:#f8f9fa; font-weight:600; text-align:left; white-space:nowrap; width:120px; font-size:14px;';
const tdStyle = 'border:1px solid #333; padding:10px 14px; font-size:14px;';
const thStyle = 'border:1px solid #333; padding:14px 16px; background:#f8f9fa; font-weight:600; text-align:left; white-space:nowrap; width:130px; font-size:15px;';
const tdStyle = 'border:1px solid #333; padding:14px 16px; font-size:15px;';
return `
<h1 style="text-align:center; font-size:28px; font-weight:700; letter-spacing:12px; margin-bottom:40px;">재 직 증 명 서</h1>
<h1 style="text-align:center; font-size:30px; font-weight:700; letter-spacing:14px; margin-bottom:50px;">재 직 증 명 서</h1>
<h3 style="font-size:15px; font-weight:600; margin:24px 0 10px; color:#333;">1. 인적사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:20px;">
<h3 style="font-size:16px; font-weight:600; margin:30px 0 12px; color:#333;">1. 인적사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:24px;">
<tr>
<th style="${thStyle}">성 명</th>
<td style="${tdStyle}">${e(d.name)}</td>
@@ -1506,8 +1506,8 @@ function buildCertPreviewHtml(d) {
</tr>
</table>
<h3 style="font-size:15px; font-weight:600; margin:24px 0 10px; color:#333;">2. 재직사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:20px;">
<h3 style="font-size:16px; font-weight:600; margin:30px 0 12px; color:#333;">2. 재직사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:24px;">
<tr>
<th style="${thStyle}">회 사 명</th>
<td style="${tdStyle}" colspan="3">${e(d.company)}</td>
@@ -1528,25 +1528,25 @@ function buildCertPreviewHtml(d) {
</tr>
</table>
<h3 style="font-size:15px; font-weight:600; margin:24px 0 10px; color:#333;">3. 발급정보</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:32px;">
<h3 style="font-size:16px; font-weight:600; margin:30px 0 12px; color:#333;">3. 발급정보</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:40px;">
<tr>
<th style="${thStyle}">사용용도</th>
<td style="${tdStyle}" colspan="3">${e(d.purpose)}</td>
</tr>
</table>
<p style="text-align:center; font-size:15px; line-height:2; margin:36px 0;">
<p style="text-align:center; font-size:16px; line-height:2; margin:50px 0;">
위 사항을 증명합니다.
</p>
<p style="text-align:center; font-size:15px; font-weight:500; margin-bottom:48px;">
<p style="text-align:center; font-size:16px; font-weight:500; margin-bottom:60px;">
${e(d.issueDateFormatted)}
</p>
<div style="text-align:center; margin-top:32px;">
<p style="font-size:16px; font-weight:600; margin-bottom:8px;">${e(d.company)}</p>
<p style="font-size:14px; color:#555;">대표이사 &nbsp;&nbsp; ${e(d.ceoName)} &nbsp;&nbsp; (인)</p>
<div style="text-align:center; margin-top:40px;">
<p style="font-size:18px; font-weight:600; margin-bottom:8px;">${e(d.company)}</p>
<p style="font-size:15px; color:#555;">대표이사 &nbsp;&nbsp; ${e(d.ceoName)} &nbsp;&nbsp; (인)</p>
</div>
`;
}

View File

@@ -750,42 +750,42 @@ function printCertShowPreview() {
const content = document.getElementById('cert-show-preview-content').innerHTML;
const win = window.open('', '_blank', 'width=800,height=1000');
win.document.write('<html><head><title>재직증명서</title>');
win.document.write('<style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:48px 56px;margin:0;} table{border-collapse:collapse;width:100%;} th,td{border:1px solid #333;padding:10px 14px;font-size:14px;} th{background:#f8f9fa;font-weight:600;text-align:left;white-space:nowrap;width:120px;} @media print{body{padding:40px 48px;}}</style>');
win.document.write('</head><body>');
win.document.write('<style>@page{size:A4;margin:0;} body{font-family:"Pretendard","Malgun Gothic",sans-serif;margin:0;padding:0;} .cert-page{padding:80px 56px 60px;box-sizing:border-box;} table{border-collapse:collapse;width:100%;} th,td{border:1px solid #333;padding:14px 16px;font-size:15px;} th{background:#f8f9fa;font-weight:600;text-align:left;white-space:nowrap;width:130px;}</style>');
win.document.write('</head><body><div class="cert-page">');
win.document.write(content);
win.document.write('</body></html>');
win.document.write('</div></body></html>');
win.document.close();
win.onload = function() { win.print(); };
}
function _buildCertHtml(d) {
const e = (s) => { const div = document.createElement('div'); div.textContent = s; return div.innerHTML; };
const thStyle = 'border:1px solid #333; padding:10px 14px; background:#f8f9fa; font-weight:600; text-align:left; white-space:nowrap; width:120px; font-size:14px;';
const tdStyle = 'border:1px solid #333; padding:10px 14px; font-size:14px;';
const thStyle = 'border:1px solid #333; padding:14px 16px; background:#f8f9fa; font-weight:600; text-align:left; white-space:nowrap; width:130px; font-size:15px;';
const tdStyle = 'border:1px solid #333; padding:14px 16px; font-size:15px;';
return `
<h1 style="text-align:center; font-size:28px; font-weight:700; letter-spacing:12px; margin-bottom:40px;">재 직 증 명 서</h1>
<h3 style="font-size:15px; font-weight:600; margin:24px 0 10px; color:#333;">1. 인적사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:20px;">
<h1 style="text-align:center; font-size:30px; font-weight:700; letter-spacing:14px; margin-bottom:50px;">재 직 증 명 서</h1>
<h3 style="font-size:16px; font-weight:600; margin:30px 0 12px; color:#333;">1. 인적사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:24px;">
<tr><th style="${thStyle}">성 명</th><td style="${tdStyle}">${e(d.name)}</td><th style="${thStyle}">주민등록번호</th><td style="${tdStyle}">${e(d.resident)}</td></tr>
<tr><th style="${thStyle}">주 소</th><td style="${tdStyle}" colspan="3">${e(d.address)}</td></tr>
</table>
<h3 style="font-size:15px; font-weight:600; margin:24px 0 10px; color:#333;">2. 재직사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:20px;">
<h3 style="font-size:16px; font-weight:600; margin:30px 0 12px; color:#333;">2. 재직사항</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:24px;">
<tr><th style="${thStyle}">회 사 명</th><td style="${tdStyle}" colspan="3">${e(d.company)}</td></tr>
<tr><th style="${thStyle}">사업자번호</th><td style="${tdStyle}" colspan="3">${e(d.businessNum)}</td></tr>
<tr><th style="${thStyle}">근무부서</th><td style="${tdStyle}">${e(d.department)}</td><th style="${thStyle}">직 급</th><td style="${tdStyle}">${e(d.position)}</td></tr>
<tr><th style="${thStyle}">재직기간</th><td style="${tdStyle}" colspan="3">${e(d.hireDate)}</td></tr>
</table>
<h3 style="font-size:15px; font-weight:600; margin:24px 0 10px; color:#333;">3. 발급정보</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:32px;">
<h3 style="font-size:16px; font-weight:600; margin:30px 0 12px; color:#333;">3. 발급정보</h3>
<table style="border-collapse:collapse; width:100%; margin-bottom:40px;">
<tr><th style="${thStyle}">사용용도</th><td style="${tdStyle}" colspan="3">${e(d.purpose)}</td></tr>
</table>
<p style="text-align:center; font-size:15px; line-height:2; margin:36px 0;">위 사항을 증명합니다.</p>
<p style="text-align:center; font-size:15px; font-weight:500; margin-bottom:48px;">${e(d.issueDateFormatted)}</p>
<div style="text-align:center; margin-top:32px;">
<p style="font-size:16px; font-weight:600; margin-bottom:8px;">${e(d.company)}</p>
<p style="font-size:14px; color:#555;">대표이사 &nbsp;&nbsp; ${e(d.ceoName)} &nbsp;&nbsp; (인)</p>
<p style="text-align:center; font-size:16px; line-height:2; margin:50px 0;">위 사항을 증명합니다.</p>
<p style="text-align:center; font-size:16px; font-weight:500; margin-bottom:60px;">${e(d.issueDateFormatted)}</p>
<div style="text-align:center; margin-top:40px;">
<p style="font-size:18px; font-weight:600; margin-bottom:8px;">${e(d.company)}</p>
<p style="font-size:15px; color:#555;">대표이사 &nbsp;&nbsp; ${e(d.ceoName)} &nbsp;&nbsp; (인)</p>
</div>
`;
}