feat: [approvals] 사용인감계 양식 추가
- 증명서 카테고리에 사용인감계(seal_usage) 양식 등록 - 입력 폼: 사용일자, 인감종류, 용도, 제출처, 비고 - 회사 정보 자동 로드 (테넌트 정보 기반) - 미리보기/인쇄 기능 (원본 DOCX 유사 레이아웃) - create/edit/show 3개 페이지 모두 지원
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
|
||||
use App\Models\Finance\BankAccount;
|
||||
use App\Models\Finance\CorporateCard;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use App\Models\Tenants\TenantSetting;
|
||||
use App\Services\ApprovalService;
|
||||
use App\Services\HR\LeaveService;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -41,8 +43,9 @@ public function create(Request $request): View|Response
|
||||
$lines = $this->service->getApprovalLines();
|
||||
[$cards, $accounts] = $this->getCardAndAccountData();
|
||||
$employees = app(LeaveService::class)->getActiveEmployees();
|
||||
$tenantInfo = $this->getTenantInfo();
|
||||
|
||||
return view('approvals.create', compact('forms', 'lines', 'cards', 'accounts', 'employees'));
|
||||
return view('approvals.create', compact('forms', 'lines', 'cards', 'accounts', 'employees', 'tenantInfo'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,8 +67,9 @@ public function edit(Request $request, int $id): View|Response
|
||||
$lines = $this->service->getApprovalLines();
|
||||
[$cards, $accounts] = $this->getCardAndAccountData();
|
||||
$employees = app(LeaveService::class)->getActiveEmployees();
|
||||
$tenantInfo = $this->getTenantInfo();
|
||||
|
||||
return view('approvals.edit', compact('approval', 'forms', 'lines', 'cards', 'accounts', 'employees'));
|
||||
return view('approvals.edit', compact('approval', 'forms', 'lines', 'cards', 'accounts', 'employees', 'tenantInfo'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,6 +122,31 @@ public function completed(Request $request): View|Response
|
||||
return view('approvals.completed');
|
||||
}
|
||||
|
||||
private function getTenantInfo(): array
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
$tenant = Tenant::find($tenantId);
|
||||
|
||||
if (! $tenant) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$displaySetting = TenantSetting::withoutGlobalScopes()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('setting_group', 'company')
|
||||
->where('setting_key', 'display_company_name')
|
||||
->first();
|
||||
$displayName = $displaySetting?->setting_value ?? '';
|
||||
|
||||
return [
|
||||
'company_name' => ! empty($displayName) ? $displayName : ($tenant->company_name ?? ''),
|
||||
'business_num' => $tenant->business_num ?? '',
|
||||
'ceo_name' => $tenant->ceo_name ?? '',
|
||||
'address' => $tenant->address ?? '',
|
||||
'phone' => $tenant->phone ?? '',
|
||||
];
|
||||
}
|
||||
|
||||
private function getCardAndAccountData(): array
|
||||
{
|
||||
$tenantId = session('selected_tenant_id');
|
||||
|
||||
@@ -130,6 +130,11 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-
|
||||
'employees' => $employees ?? collect(),
|
||||
])
|
||||
|
||||
{{-- 사용인감계 전용 폼 --}}
|
||||
@include('approvals.partials._seal-usage-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
])
|
||||
|
||||
{{-- 지출결의서 전용 폼 --}}
|
||||
@include('approvals.partials._expense-form', [
|
||||
'initialData' => [],
|
||||
@@ -304,6 +309,11 @@ class="p-1 text-gray-400 hover:text-gray-600 transition">
|
||||
color: 'border-gray-300 bg-gray-50', titleColor: 'text-gray-800', textColor: 'text-gray-600',
|
||||
text: '퇴직 의사를 공식적으로 표명하는 문서입니다. 사직 사유와 희망 퇴직일을 기재하며, 결재 완료 후 퇴직 절차가 진행됩니다.',
|
||||
},
|
||||
seal_usage: {
|
||||
title: '사용인감계', icon: '🔏',
|
||||
color: 'border-rose-200 bg-rose-50', titleColor: 'text-rose-800', textColor: 'text-rose-600',
|
||||
text: '법인인감, 사용인감 등 회사 인감의 사용을 신청하는 문서입니다. 인감 종류, 용도, 제출처를 기재하며, 승인 후 인감을 사용할 수 있습니다.',
|
||||
},
|
||||
pr_expense: {
|
||||
title: '지출품의서', icon: '📋',
|
||||
color: 'border-orange-200 bg-orange-50', titleColor: 'text-orange-800', textColor: 'text-orange-700',
|
||||
@@ -335,7 +345,7 @@ class="p-1 text-gray-400 hover:text-gray-600 transition">
|
||||
const formCategoryMap = {
|
||||
BUSINESS_DRAFT: '일반',
|
||||
leave: '인사/근태', attendance_request: '인사/근태', resignation: '인사/근태', reason_report: '인사/근태',
|
||||
employment_cert: '증명서', career_cert: '증명서', appointment_cert: '증명서',
|
||||
employment_cert: '증명서', career_cert: '증명서', appointment_cert: '증명서', seal_usage: '증명서',
|
||||
pr_expense: '품의', pr_contract: '품의', pr_purchase: '품의', pr_trip: '품의', pr_settlement: '품의',
|
||||
expense: '재무',
|
||||
};
|
||||
@@ -421,6 +431,7 @@ function updateFormDescription(formId) {
|
||||
let isCareerCertForm = false;
|
||||
let isAppointmentCertForm = false;
|
||||
let isResignationForm = false;
|
||||
let isSealUsageForm = false;
|
||||
|
||||
// 양식코드별 표시할 유형 목록
|
||||
const leaveTypesByFormCode = {
|
||||
@@ -669,6 +680,7 @@ function switchFormMode(formId) {
|
||||
const careerCertContainer = document.getElementById('career-cert-form-container');
|
||||
const appointmentCertContainer = document.getElementById('appointment-cert-form-container');
|
||||
const resignationContainer = document.getElementById('resignation-form-container');
|
||||
const sealUsageContainer = document.getElementById('seal-usage-form-container');
|
||||
const bodyArea = document.getElementById('body-area');
|
||||
const expenseLoadBtn = document.getElementById('expense-load-btn');
|
||||
|
||||
@@ -682,6 +694,7 @@ function switchFormMode(formId) {
|
||||
careerCertContainer.style.display = 'none';
|
||||
appointmentCertContainer.style.display = 'none';
|
||||
resignationContainer.style.display = 'none';
|
||||
sealUsageContainer.style.display = 'none';
|
||||
expenseLoadBtn.style.display = 'none';
|
||||
bodyArea.style.display = 'none';
|
||||
isExpenseForm = false;
|
||||
@@ -691,6 +704,7 @@ function switchFormMode(formId) {
|
||||
isCareerCertForm = false;
|
||||
isAppointmentCertForm = false;
|
||||
isResignationForm = false;
|
||||
isSealUsageForm = false;
|
||||
|
||||
if (code === 'expense') {
|
||||
isExpenseForm = true;
|
||||
@@ -750,6 +764,9 @@ function switchFormMode(formId) {
|
||||
resignationContainer.style.display = '';
|
||||
const rgUserId = document.getElementById('rg-user-id').value;
|
||||
if (rgUserId) loadResignationInfo(rgUserId);
|
||||
} else if (code === 'seal_usage') {
|
||||
isSealUsageForm = true;
|
||||
sealUsageContainer.style.display = '';
|
||||
} else {
|
||||
bodyArea.style.display = '';
|
||||
}
|
||||
@@ -760,7 +777,7 @@ function applyBodyTemplate(formId) {
|
||||
switchFormMode(formId);
|
||||
|
||||
// 전용 폼이면 제목을 양식명으로 설정하고 body template 적용 건너뜀
|
||||
if (isExpenseForm || isPurchaseRequestForm || isLeaveForm || isCertForm || isCareerCertForm || isAppointmentCertForm || isResignationForm) {
|
||||
if (isExpenseForm || isPurchaseRequestForm || isLeaveForm || isCertForm || isCareerCertForm || isAppointmentCertForm || isResignationForm || isSealUsageForm) {
|
||||
const titleEl = document.getElementById('title');
|
||||
const formSelect = document.getElementById('form_id');
|
||||
titleEl.value = formSelect.options[formSelect.selectedIndex].text;
|
||||
@@ -954,6 +971,30 @@ function applyBodyTemplate(formId) {
|
||||
issue_date: document.getElementById('ac-issue-date').value,
|
||||
};
|
||||
formBody = null;
|
||||
} else if (isSealUsageForm) {
|
||||
const suPurpose = document.getElementById('su-purpose').value.trim();
|
||||
if (!suPurpose) {
|
||||
showToast('용도를 입력해주세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
const suSubmitTo = document.getElementById('su-submit-to').value.trim();
|
||||
if (!suSubmitTo) {
|
||||
showToast('제출처를 입력해주세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
formContent = {
|
||||
usage_date: document.getElementById('su-usage-date').value,
|
||||
seal_type: getSealUsageType(),
|
||||
purpose: suPurpose,
|
||||
submit_to: suSubmitTo,
|
||||
remarks: document.getElementById('su-remarks').value.trim(),
|
||||
company_name: document.getElementById('su-company-name').value,
|
||||
business_num: document.getElementById('su-business-num').value,
|
||||
ceo_name: document.getElementById('su-ceo-name').value,
|
||||
company_address: document.getElementById('su-company-address').value,
|
||||
};
|
||||
formBody = null;
|
||||
} else if (isResignationForm) {
|
||||
const reason = getResignationReason();
|
||||
if (!reason) {
|
||||
@@ -1785,5 +1826,104 @@ function buildCertPreviewHtml(d) {
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 사용인감계 관련 함수
|
||||
// =========================================================================
|
||||
|
||||
document.getElementById('su-seal-type')?.addEventListener('change', function() {
|
||||
const customWrap = document.getElementById('su-seal-type-custom-wrap');
|
||||
if (this.value === '__custom__') {
|
||||
customWrap.style.display = '';
|
||||
document.getElementById('su-seal-type-custom').focus();
|
||||
} else {
|
||||
customWrap.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
function getSealUsageType() {
|
||||
const sel = document.getElementById('su-seal-type');
|
||||
if (sel.value === '__custom__') {
|
||||
return document.getElementById('su-seal-type-custom').value.trim() || '기타';
|
||||
}
|
||||
return sel.value;
|
||||
}
|
||||
|
||||
function buildSealUsagePreviewHtml(data) {
|
||||
const e = (s) => s ? String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') : '-';
|
||||
return `
|
||||
<div style="text-align:center; margin-bottom:48px;">
|
||||
<h1 style="font-size:28px; font-weight:700; letter-spacing:12px; margin:0;">사 용 인 감 계</h1>
|
||||
</div>
|
||||
|
||||
<table style="width:100%; border-collapse:collapse; margin-bottom:36px; font-size:14px;">
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; width:120px; text-align:center;">사용일자</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.usage_date)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">인감종류</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.seal_type)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">용 도</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.purpose)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">제출처</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.submit_to)}</td>
|
||||
</tr>
|
||||
${data.remarks ? `<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">비 고</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.remarks)}</td>
|
||||
</tr>` : ''}
|
||||
</table>
|
||||
|
||||
<p style="text-align:center; font-size:13px; color:#666; margin-bottom:36px;">
|
||||
위와 같이 인감 사용을 신청하오니 허가하여 주시기 바랍니다.
|
||||
</p>
|
||||
|
||||
<div style="margin-top:40px; padding:20px 24px; border:1px solid #ddd; border-radius:6px; background:#fafafa;">
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">상 호</span>: ${e(data.company_name)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">사업자등록번호</span>: ${e(data.business_num)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">주 소</span>: ${e(data.company_address)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">대표이사</span>: ${e(data.ceo_name)}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function openSealUsagePreview() {
|
||||
const data = {
|
||||
usage_date: document.getElementById('su-usage-date').value,
|
||||
seal_type: getSealUsageType(),
|
||||
purpose: document.getElementById('su-purpose').value,
|
||||
submit_to: document.getElementById('su-submit-to').value,
|
||||
remarks: document.getElementById('su-remarks').value,
|
||||
company_name: document.getElementById('su-company-name').value,
|
||||
business_num: document.getElementById('su-business-num').value,
|
||||
ceo_name: document.getElementById('su-ceo-name').value,
|
||||
company_address: document.getElementById('su-company-address').value,
|
||||
};
|
||||
document.getElementById('seal-usage-preview-content').innerHTML = buildSealUsagePreviewHtml(data);
|
||||
document.getElementById('seal-usage-preview-modal').style.display = '';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeSealUsagePreview() {
|
||||
document.getElementById('seal-usage-preview-modal').style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
function printSealUsagePreview() {
|
||||
const content = document.getElementById('seal-usage-preview-content').innerHTML;
|
||||
const win = window.open('', '_blank');
|
||||
win.document.write('<html><head><title>사용인감계</title>');
|
||||
win.document.write('<style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:48px 56px;margin:0;}@media print{body{padding:40px 48px;}}</style>');
|
||||
win.document.write('</head><body>');
|
||||
win.document.write(content);
|
||||
win.document.write('</body></html>');
|
||||
win.document.close();
|
||||
win.print();
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@@ -148,6 +148,11 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-
|
||||
'employees' => $employees ?? collect(),
|
||||
])
|
||||
|
||||
{{-- 사용인감계 전용 폼 --}}
|
||||
@include('approvals.partials._seal-usage-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
])
|
||||
|
||||
{{-- 지출결의서 전용 폼 --}}
|
||||
@php
|
||||
$existingFiles = [];
|
||||
@@ -284,6 +289,7 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm fon
|
||||
let isExpenseForm = false;
|
||||
let isPurchaseRequestForm = false;
|
||||
let isCertForm = false;
|
||||
let isSealUsageForm = false;
|
||||
|
||||
const formDescriptions = {
|
||||
BUSINESS_DRAFT: {
|
||||
@@ -331,6 +337,11 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm fon
|
||||
color: 'border-gray-300 bg-gray-50', titleColor: 'text-gray-800', textColor: 'text-gray-600',
|
||||
text: '퇴직 의사를 공식적으로 표명하는 문서입니다. 사직 사유와 희망 퇴직일을 기재하며, 결재 완료 후 퇴직 절차가 진행됩니다.',
|
||||
},
|
||||
seal_usage: {
|
||||
title: '사용인감계', icon: '🔏',
|
||||
color: 'border-rose-200 bg-rose-50', titleColor: 'text-rose-800', textColor: 'text-rose-600',
|
||||
text: '법인인감, 사용인감 등 회사 인감의 사용을 신청하는 문서입니다. 인감 종류, 용도, 제출처를 기재하며, 승인 후 인감을 사용할 수 있습니다.',
|
||||
},
|
||||
pr_expense: {
|
||||
title: '지출품의서', icon: '📋',
|
||||
color: 'border-orange-200 bg-orange-50', titleColor: 'text-orange-800', textColor: 'text-orange-700',
|
||||
@@ -362,7 +373,7 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm fon
|
||||
const formCategoryMap = {
|
||||
BUSINESS_DRAFT: '일반',
|
||||
leave: '인사/근태', attendance_request: '인사/근태', resignation: '인사/근태', reason_report: '인사/근태',
|
||||
employment_cert: '증명서', career_cert: '증명서', appointment_cert: '증명서',
|
||||
employment_cert: '증명서', career_cert: '증명서', appointment_cert: '증명서', seal_usage: '증명서',
|
||||
pr_expense: '품의', pr_contract: '품의', pr_purchase: '품의', pr_trip: '품의', pr_settlement: '품의',
|
||||
expense: '재무',
|
||||
};
|
||||
@@ -601,15 +612,18 @@ function switchFormMode(formId) {
|
||||
const expenseContainer = document.getElementById('expense-form-container');
|
||||
const purchaseRequestContainer = document.getElementById('purchase-request-form-container');
|
||||
const certContainer = document.getElementById('cert-form-container');
|
||||
const sealUsageContainer = document.getElementById('seal-usage-form-container');
|
||||
const bodyArea = document.getElementById('body-area');
|
||||
|
||||
expenseContainer.style.display = 'none';
|
||||
purchaseRequestContainer.style.display = 'none';
|
||||
certContainer.style.display = 'none';
|
||||
sealUsageContainer.style.display = 'none';
|
||||
bodyArea.style.display = 'none';
|
||||
isExpenseForm = false;
|
||||
isPurchaseRequestForm = false;
|
||||
isCertForm = false;
|
||||
isSealUsageForm = false;
|
||||
|
||||
if (code === 'expense') {
|
||||
isExpenseForm = true;
|
||||
@@ -626,6 +640,9 @@ function switchFormMode(formId) {
|
||||
certContainer.style.display = '';
|
||||
const certUserId = document.getElementById('cert-user-id').value;
|
||||
if (certUserId) loadCertInfo(certUserId);
|
||||
} else if (code === 'seal_usage') {
|
||||
isSealUsageForm = true;
|
||||
sealUsageContainer.style.display = '';
|
||||
} else {
|
||||
bodyArea.style.display = '';
|
||||
}
|
||||
@@ -636,7 +653,7 @@ function applyBodyTemplate(formId) {
|
||||
switchFormMode(formId);
|
||||
|
||||
// 전용 폼이면 제목만 자동 설정하고 body template 적용 건너뜀
|
||||
if (isExpenseForm || isPurchaseRequestForm || isCertForm) {
|
||||
if (isExpenseForm || isPurchaseRequestForm || isCertForm || isSealUsageForm) {
|
||||
const titleEl = document.getElementById('title');
|
||||
if (!titleEl.value.trim()) {
|
||||
const formSelect = document.getElementById('form_id');
|
||||
@@ -731,8 +748,31 @@ function applyBodyTemplate(formId) {
|
||||
}
|
||||
}
|
||||
|
||||
// 사용인감계 기존 데이터 복원
|
||||
if (isSealUsageForm) {
|
||||
const suContent = @json($approval->content ?? []);
|
||||
if (suContent.usage_date) {
|
||||
document.getElementById('su-usage-date').value = suContent.usage_date || '';
|
||||
document.getElementById('su-purpose').value = suContent.purpose || '';
|
||||
document.getElementById('su-submit-to').value = suContent.submit_to || '';
|
||||
document.getElementById('su-remarks').value = suContent.remarks || '';
|
||||
|
||||
// 인감종류 복원
|
||||
const sealTypeSelect = document.getElementById('su-seal-type');
|
||||
const sealType = suContent.seal_type || '';
|
||||
const predefinedSeals = ['법인인감', '사용인감', '대표이사 인감', '직인'];
|
||||
if (predefinedSeals.includes(sealType)) {
|
||||
sealTypeSelect.value = sealType;
|
||||
} else if (sealType) {
|
||||
sealTypeSelect.value = '__custom__';
|
||||
document.getElementById('su-seal-type-custom-wrap').style.display = '';
|
||||
document.getElementById('su-seal-type-custom').value = sealType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 전용 폼이 아닌 경우에만 Quill 편집기 자동 활성화
|
||||
if (!isExpenseForm && !isPurchaseRequestForm && !isCertForm) {
|
||||
if (!isExpenseForm && !isPurchaseRequestForm && !isCertForm && !isSealUsageForm) {
|
||||
const existingBody = document.getElementById('body').value;
|
||||
if (/<[a-z][\s\S]*>/i.test(existingBody)) {
|
||||
document.getElementById('useEditor').checked = true;
|
||||
@@ -806,6 +846,30 @@ function applyBodyTemplate(formId) {
|
||||
issue_date: document.getElementById('cert-issue-date').value,
|
||||
};
|
||||
formBody = null;
|
||||
} else if (isSealUsageForm) {
|
||||
const suPurpose = document.getElementById('su-purpose').value.trim();
|
||||
if (!suPurpose) {
|
||||
showToast('용도를 입력해주세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
const suSubmitTo = document.getElementById('su-submit-to').value.trim();
|
||||
if (!suSubmitTo) {
|
||||
showToast('제출처를 입력해주세요.', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
formContent = {
|
||||
usage_date: document.getElementById('su-usage-date').value,
|
||||
seal_type: getSealUsageType(),
|
||||
purpose: suPurpose,
|
||||
submit_to: suSubmitTo,
|
||||
remarks: document.getElementById('su-remarks').value.trim(),
|
||||
company_name: document.getElementById('su-company-name').value,
|
||||
business_num: document.getElementById('su-business-num').value,
|
||||
ceo_name: document.getElementById('su-ceo-name').value,
|
||||
company_address: document.getElementById('su-company-address').value,
|
||||
};
|
||||
formBody = null;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
@@ -1044,5 +1108,104 @@ function buildCertPreviewHtml(d) {
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 사용인감계 관련 함수
|
||||
// =========================================================================
|
||||
|
||||
document.getElementById('su-seal-type')?.addEventListener('change', function() {
|
||||
const customWrap = document.getElementById('su-seal-type-custom-wrap');
|
||||
if (this.value === '__custom__') {
|
||||
customWrap.style.display = '';
|
||||
document.getElementById('su-seal-type-custom').focus();
|
||||
} else {
|
||||
customWrap.style.display = 'none';
|
||||
}
|
||||
});
|
||||
|
||||
function getSealUsageType() {
|
||||
const sel = document.getElementById('su-seal-type');
|
||||
if (sel.value === '__custom__') {
|
||||
return document.getElementById('su-seal-type-custom').value.trim() || '기타';
|
||||
}
|
||||
return sel.value;
|
||||
}
|
||||
|
||||
function buildSealUsagePreviewHtml(data) {
|
||||
const e = (s) => s ? String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') : '-';
|
||||
return `
|
||||
<div style="text-align:center; margin-bottom:48px;">
|
||||
<h1 style="font-size:28px; font-weight:700; letter-spacing:12px; margin:0;">사 용 인 감 계</h1>
|
||||
</div>
|
||||
|
||||
<table style="width:100%; border-collapse:collapse; margin-bottom:36px; font-size:14px;">
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; width:120px; text-align:center;">사용일자</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.usage_date)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">인감종류</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.seal_type)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">용 도</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.purpose)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">제출처</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.submit_to)}</td>
|
||||
</tr>
|
||||
${data.remarks ? `<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">비 고</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.remarks)}</td>
|
||||
</tr>` : ''}
|
||||
</table>
|
||||
|
||||
<p style="text-align:center; font-size:13px; color:#666; margin-bottom:36px;">
|
||||
위와 같이 인감 사용을 신청하오니 허가하여 주시기 바랍니다.
|
||||
</p>
|
||||
|
||||
<div style="margin-top:40px; padding:20px 24px; border:1px solid #ddd; border-radius:6px; background:#fafafa;">
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">상 호</span>: ${e(data.company_name)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">사업자등록번호</span>: ${e(data.business_num)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">주 소</span>: ${e(data.company_address)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">대표이사</span>: ${e(data.ceo_name)}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function openSealUsagePreview() {
|
||||
const data = {
|
||||
usage_date: document.getElementById('su-usage-date').value,
|
||||
seal_type: getSealUsageType(),
|
||||
purpose: document.getElementById('su-purpose').value,
|
||||
submit_to: document.getElementById('su-submit-to').value,
|
||||
remarks: document.getElementById('su-remarks').value,
|
||||
company_name: document.getElementById('su-company-name').value,
|
||||
business_num: document.getElementById('su-business-num').value,
|
||||
ceo_name: document.getElementById('su-ceo-name').value,
|
||||
company_address: document.getElementById('su-company-address').value,
|
||||
};
|
||||
document.getElementById('seal-usage-preview-content').innerHTML = buildSealUsagePreviewHtml(data);
|
||||
document.getElementById('seal-usage-preview-modal').style.display = '';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeSealUsagePreview() {
|
||||
document.getElementById('seal-usage-preview-modal').style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
function printSealUsagePreview() {
|
||||
const content = document.getElementById('seal-usage-preview-content').innerHTML;
|
||||
const win = window.open('', '_blank');
|
||||
win.document.write('<html><head><title>사용인감계</title>');
|
||||
win.document.write('<style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:48px 56px;margin:0;}@media print{body{padding:40px 48px;}}</style>');
|
||||
win.document.write('</head><body>');
|
||||
win.document.write(content);
|
||||
win.document.write('</body></html>');
|
||||
win.document.close();
|
||||
win.print();
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
139
resources/views/approvals/partials/_seal-usage-form.blade.php
Normal file
139
resources/views/approvals/partials/_seal-usage-form.blade.php
Normal file
@@ -0,0 +1,139 @@
|
||||
{{--
|
||||
사용인감계 전용 폼
|
||||
Props:
|
||||
$tenantInfo (array) - 테넌트(회사) 정보
|
||||
--}}
|
||||
@php
|
||||
$tenantInfo = $tenantInfo ?? [];
|
||||
@endphp
|
||||
|
||||
<div id="seal-usage-form-container" style="display: none;" class="mb-4">
|
||||
<input type="hidden" id="su-company-name" value="{{ $tenantInfo['company_name'] ?? '' }}">
|
||||
<input type="hidden" id="su-business-num" value="{{ $tenantInfo['business_num'] ?? '' }}">
|
||||
<input type="hidden" id="su-ceo-name" value="{{ $tenantInfo['ceo_name'] ?? '' }}">
|
||||
<input type="hidden" id="su-company-address" value="{{ $tenantInfo['address'] ?? '' }}">
|
||||
|
||||
<div class="space-y-4">
|
||||
{{-- 인감 사용 정보 --}}
|
||||
<div class="border border-gray-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-gray-50 px-4 py-2 border-b border-gray-200">
|
||||
<h3 class="text-sm font-semibold text-gray-700">인감 사용 정보</h3>
|
||||
</div>
|
||||
<div class="p-4 space-y-3">
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<div style="flex: 1 1 200px; max-width: 250px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">사용일자 <span class="text-red-500">*</span></label>
|
||||
<input type="date" id="su-usage-date" value="{{ now()->format('Y-m-d') }}"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div style="flex: 1 1 250px; max-width: 300px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">인감종류 <span class="text-red-500">*</span></label>
|
||||
<select id="su-seal-type"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
<option value="법인인감">법인인감</option>
|
||||
<option value="사용인감">사용인감</option>
|
||||
<option value="대표이사 인감">대표이사 인감</option>
|
||||
<option value="직인">직인</option>
|
||||
<option value="__custom__">기타 (직접입력)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="su-seal-type-custom-wrap" style="flex: 1 1 200px; max-width: 250px; display: none;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">직접입력</label>
|
||||
<input type="text" id="su-seal-type-custom" placeholder="인감종류를 입력하세요"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">용도 <span class="text-red-500">*</span></label>
|
||||
<input type="text" id="su-purpose" placeholder="예: 계약서 날인, 인감증명서 발급 등"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">제출처 <span class="text-red-500">*</span></label>
|
||||
<input type="text" id="su-submit-to" placeholder="예: 거래처명, 관공서명 등"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">비고</label>
|
||||
<textarea id="su-remarks" rows="2" placeholder="추가 참고사항 (선택)"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 회사 정보 (읽기 전용) --}}
|
||||
<div class="border border-gray-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-gray-50 px-4 py-2 border-b border-gray-200">
|
||||
<h3 class="text-sm font-semibold text-gray-700">회사 정보</h3>
|
||||
</div>
|
||||
<div class="p-4 space-y-3">
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<div style="flex: 1 1 250px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">상호</label>
|
||||
<input type="text" id="su-company-display" readonly value="{{ $tenantInfo['company_name'] ?? '' }}"
|
||||
class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm bg-gray-50 text-gray-700">
|
||||
</div>
|
||||
<div style="flex: 1 1 200px; max-width: 250px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">사업자등록번호</label>
|
||||
<input type="text" id="su-business-display" readonly value="{{ $tenantInfo['business_num'] ?? '' }}"
|
||||
class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm bg-gray-50 text-gray-700">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">주소</label>
|
||||
<input type="text" id="su-address-display" readonly value="{{ $tenantInfo['address'] ?? '' }}"
|
||||
class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm bg-gray-50 text-gray-700">
|
||||
</div>
|
||||
<div style="max-width: 250px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">대표이사</label>
|
||||
<input type="text" id="su-ceo-display" readonly value="{{ $tenantInfo['ceo_name'] ?? '' }}"
|
||||
class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm bg-gray-50 text-gray-700">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 미리보기 버튼 --}}
|
||||
<div class="flex justify-end">
|
||||
<button type="button" onclick="openSealUsagePreview()"
|
||||
class="px-3 py-2 bg-indigo-50 text-indigo-600 hover:bg-indigo-100 border border-indigo-200 rounded-lg text-sm font-medium transition inline-flex items-center gap-1">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
||||
</svg>
|
||||
미리보기
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 사용인감계 미리보기 모달 --}}
|
||||
<div id="seal-usage-preview-modal" style="display: none;" class="fixed inset-0 z-50">
|
||||
<div class="absolute inset-0 bg-black/50" onclick="closeSealUsagePreview()"></div>
|
||||
<div class="relative flex items-center justify-center min-h-full p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full overflow-hidden relative" style="max-width: 700px;">
|
||||
<div class="flex items-center justify-between px-5 py-3 border-b border-gray-200 bg-gray-50">
|
||||
<h3 class="text-base font-semibold text-gray-800">사용인감계 미리보기</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" onclick="printSealUsagePreview()"
|
||||
class="px-3 py-1.5 bg-white border border-gray-300 hover:bg-gray-50 rounded-lg text-xs font-medium transition inline-flex items-center gap-1">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"/>
|
||||
</svg>
|
||||
인쇄
|
||||
</button>
|
||||
<button type="button" onclick="closeSealUsagePreview()"
|
||||
class="p-1 text-gray-400 hover:text-gray-600 transition">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-y-auto" style="max-height: 80vh;">
|
||||
<div id="seal-usage-preview-content" style="padding: 48px 56px; font-family: 'Pretendard', 'Malgun Gothic', sans-serif;">
|
||||
{{-- JS에서 동적으로 채움 --}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
109
resources/views/approvals/partials/_seal-usage-show.blade.php
Normal file
109
resources/views/approvals/partials/_seal-usage-show.blade.php
Normal file
@@ -0,0 +1,109 @@
|
||||
{{--
|
||||
사용인감계 읽기전용 렌더링
|
||||
Props:
|
||||
$content (array) - approvals.content JSON
|
||||
--}}
|
||||
<div class="space-y-4">
|
||||
{{-- 미리보기 버튼 --}}
|
||||
<div class="flex justify-end gap-2">
|
||||
<button type="button" onclick="openSealUsageShowPreview()"
|
||||
class="px-3 py-1.5 bg-indigo-50 text-indigo-600 hover:bg-indigo-100 border border-indigo-200 rounded-lg text-sm font-medium transition inline-flex items-center gap-1">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/>
|
||||
</svg>
|
||||
사용인감계 미리보기
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{{-- 인감 사용 정보 --}}
|
||||
<div class="border border-gray-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-gray-50 px-4 py-2 border-b border-gray-200">
|
||||
<h3 class="text-sm font-semibold text-gray-700">인감 사용 정보</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">사용일자</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['usage_date'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">인감종류</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['seal_type'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div style="grid-column: 1 / -1;">
|
||||
<span class="text-xs text-gray-500">용도</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['purpose'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div style="grid-column: 1 / -1;">
|
||||
<span class="text-xs text-gray-500">제출처</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['submit_to'] ?? '-' }}</div>
|
||||
</div>
|
||||
@if(!empty($content['remarks']))
|
||||
<div style="grid-column: 1 / -1;">
|
||||
<span class="text-xs text-gray-500">비고</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['remarks'] }}</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 회사 정보 --}}
|
||||
<div class="border border-gray-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-gray-50 px-4 py-2 border-b border-gray-200">
|
||||
<h3 class="text-sm font-semibold text-gray-700">회사 정보</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="grid gap-3" style="grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));">
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">상호</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['company_name'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">사업자등록번호</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['business_num'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div style="grid-column: 1 / -1;">
|
||||
<span class="text-xs text-gray-500">주소</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['company_address'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">대표이사</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['ceo_name'] ?? '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 미리보기 모달 --}}
|
||||
<div id="seal-usage-show-preview-modal" style="display: none;" class="fixed inset-0 z-50">
|
||||
<div class="absolute inset-0 bg-black/50" onclick="closeSealUsageShowPreview()"></div>
|
||||
<div class="relative flex items-center justify-center min-h-full p-4">
|
||||
<div class="bg-white rounded-xl shadow-2xl w-full overflow-hidden relative" style="max-width: 700px;">
|
||||
<div class="flex items-center justify-between px-5 py-3 border-b border-gray-200 bg-gray-50">
|
||||
<h3 class="text-base font-semibold text-gray-800">사용인감계 미리보기</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" onclick="printSealUsageShowPreview()"
|
||||
class="px-3 py-1.5 bg-white border border-gray-300 hover:bg-gray-50 rounded-lg text-xs font-medium transition inline-flex items-center gap-1">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z"/>
|
||||
</svg>
|
||||
인쇄
|
||||
</button>
|
||||
<button type="button" onclick="closeSealUsageShowPreview()"
|
||||
class="p-1 text-gray-400 hover:text-gray-600 transition">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-y-auto" style="max-height: 80vh;">
|
||||
<div id="seal-usage-show-preview-content" style="padding: 48px 56px; font-family: 'Pretendard', 'Malgun Gothic', sans-serif;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,6 +92,8 @@ class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg transition
|
||||
@include('approvals.partials._appointment-cert-show', ['content' => $approval->content])
|
||||
@elseif(!empty($approval->content) && $approval->form?->code === 'resignation')
|
||||
@include('approvals.partials._resignation-show', ['content' => $approval->content])
|
||||
@elseif(!empty($approval->content) && $approval->form?->code === 'seal_usage')
|
||||
@include('approvals.partials._seal-usage-show', ['content' => $approval->content])
|
||||
@elseif($approval->body && preg_match('/<[a-z][\s\S]*>/i', $approval->body))
|
||||
<div class="prose prose-sm max-w-none text-gray-700">
|
||||
{!! strip_tags($approval->body, '<p><br><strong><b><em><i><u><s><del><h1><h2><h3><h4><h5><h6><ul><ol><li><blockquote><pre><code><a><span><div><table><thead><tbody><tr><th><td>') !!}
|
||||
@@ -793,5 +795,75 @@ function _buildCertHtml(d) {
|
||||
`;
|
||||
}
|
||||
@endif
|
||||
|
||||
@if(!empty($approval->content) && $approval->form?->code === 'seal_usage')
|
||||
const _sealUsageContent = @json($approval->content);
|
||||
|
||||
function buildSealUsageShowPreviewHtml(data) {
|
||||
const e = (s) => s ? String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') : '-';
|
||||
return `
|
||||
<div style="text-align:center; margin-bottom:48px;">
|
||||
<h1 style="font-size:28px; font-weight:700; letter-spacing:12px; margin:0;">사 용 인 감 계</h1>
|
||||
</div>
|
||||
|
||||
<table style="width:100%; border-collapse:collapse; margin-bottom:36px; font-size:14px;">
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; width:120px; text-align:center;">사용일자</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.usage_date)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">인감종류</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.seal_type)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">용 도</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.purpose)}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">제출처</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.submit_to)}</td>
|
||||
</tr>
|
||||
${data.remarks ? `<tr>
|
||||
<td style="border:1px solid #333; padding:10px 14px; background:#f8f8f8; font-weight:600; text-align:center;">비 고</td>
|
||||
<td style="border:1px solid #333; padding:10px 14px;">${e(data.remarks)}</td>
|
||||
</tr>` : ''}
|
||||
</table>
|
||||
|
||||
<p style="text-align:center; font-size:13px; color:#666; margin-bottom:36px;">
|
||||
위와 같이 인감 사용을 신청하오니 허가하여 주시기 바랍니다.
|
||||
</p>
|
||||
|
||||
<div style="margin-top:40px; padding:20px 24px; border:1px solid #ddd; border-radius:6px; background:#fafafa;">
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">상 호</span>: ${e(data.company_name)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">사업자등록번호</span>: ${e(data.business_num)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">주 소</span>: ${e(data.company_address)}</p>
|
||||
<p style="font-size:13px; margin:4px 0; color:#333;"><span style="display:inline-block; width:110px; font-weight:600;">대표이사</span>: ${e(data.ceo_name)}</p>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
function openSealUsageShowPreview() {
|
||||
document.getElementById('seal-usage-show-preview-content').innerHTML = buildSealUsageShowPreviewHtml(_sealUsageContent);
|
||||
document.getElementById('seal-usage-show-preview-modal').style.display = '';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeSealUsageShowPreview() {
|
||||
document.getElementById('seal-usage-show-preview-modal').style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
function printSealUsageShowPreview() {
|
||||
const content = document.getElementById('seal-usage-show-preview-content').innerHTML;
|
||||
const win = window.open('', '_blank');
|
||||
win.document.write('<html><head><title>사용인감계</title>');
|
||||
win.document.write('<style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:48px 56px;margin:0;}@media print{body{padding:40px 48px;}}</style>');
|
||||
win.document.write('</head><body>');
|
||||
win.document.write(content);
|
||||
win.document.write('</body></html>');
|
||||
win.document.close();
|
||||
win.print();
|
||||
}
|
||||
@endif
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
Reference in New Issue
Block a user