feat: [approval] 연차사용촉진 통지서 1차/2차 양식 추가
- 1차 통지서: 직원 선택, 연차 현황(발생/사용/잔여), 제출기한, 법적 문구 - 2차 통지서: 직원 선택, 잔여연차, 회사 지정 휴가일(다건), 법적 문구 - create/edit/show 통합 완료 - 미리보기/인쇄 기능 포함
This commit is contained in:
@@ -150,6 +150,18 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
])
|
||||
|
||||
{{-- 연차사용촉진 1차 통지서 --}}
|
||||
@include('approvals.partials._leave-promotion-1st-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
'employees' => $employees ?? collect(),
|
||||
])
|
||||
|
||||
{{-- 연차사용촉진 2차 통지서 --}}
|
||||
@include('approvals.partials._leave-promotion-2nd-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
'employees' => $employees ?? collect(),
|
||||
])
|
||||
|
||||
{{-- 견적서 전용 폼 --}}
|
||||
@include('approvals.partials._quotation-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
@@ -349,6 +361,16 @@ class="p-1 text-gray-400 hover:text-gray-600 transition">
|
||||
color: 'border-slate-300 bg-slate-50', titleColor: 'text-slate-800', textColor: 'text-slate-600',
|
||||
text: '이사회 개최 내용을 기록하는 공식 문서입니다. 일시, 장소, 출석현황, 의안, 의사경과, 기명날인 등을 기재하며, 법적 효력을 갖는 회의록입니다.',
|
||||
},
|
||||
leave_promotion_1st: {
|
||||
title: '연차사용촉진 통지서 (1차)', icon: '📅',
|
||||
color: 'border-orange-200 bg-orange-50', titleColor: 'text-orange-800', textColor: 'text-orange-600',
|
||||
text: '근로기준법 제61조에 따른 연차 사용 촉진 1차 통지서입니다. 잔여 연차 현황을 안내하고, 사용계획 제출기한을 지정하여 직원에게 통보합니다.',
|
||||
},
|
||||
leave_promotion_2nd: {
|
||||
title: '연차사용촉진 통지서 (2차)', icon: '🚨',
|
||||
color: 'border-red-200 bg-red-50', titleColor: 'text-red-800', textColor: 'text-red-600',
|
||||
text: '1차 통지 후에도 사용 시기를 제출하지 않은 직원에게 회사가 휴가일을 지정하는 2차 통지서입니다. 근로기준법 제61조에 따른 법적 효력이 있습니다.',
|
||||
},
|
||||
quotation: {
|
||||
title: '견적서', icon: '💵',
|
||||
color: 'border-green-200 bg-green-50', titleColor: 'text-green-800', textColor: 'text-green-600',
|
||||
@@ -384,7 +406,7 @@ class="p-1 text-gray-400 hover:text-gray-600 transition">
|
||||
// 2단계 분류 정의 (코드 → 카테고리)
|
||||
const formCategoryMap = {
|
||||
BUSINESS_DRAFT: '일반', official_letter: '일반',
|
||||
leave: '인사/근태', attendance_request: '인사/근태', resignation: '인사/근태', reason_report: '인사/근태', delegation: '인사/근태', board_minutes: '인사/근태',
|
||||
leave: '인사/근태', attendance_request: '인사/근태', resignation: '인사/근태', reason_report: '인사/근태', delegation: '인사/근태', board_minutes: '인사/근태', leave_promotion_1st: '인사/근태', leave_promotion_2nd: '인사/근태',
|
||||
employment_cert: '증명서', career_cert: '증명서', appointment_cert: '증명서', seal_usage: '증명서',
|
||||
pr_expense: '품의', pr_contract: '품의', pr_purchase: '품의', pr_trip: '품의', pr_settlement: '품의',
|
||||
quotation: '재무', expense: '재무',
|
||||
@@ -476,6 +498,8 @@ function updateFormDescription(formId) {
|
||||
let isBoardMinutesForm = false;
|
||||
let isQuotationForm = false;
|
||||
let isOfficialLetterForm = false;
|
||||
let isLeavePromotion1stForm = false;
|
||||
let isLeavePromotion2ndForm = false;
|
||||
|
||||
// 양식코드별 표시할 유형 목록
|
||||
const leaveTypesByFormCode = {
|
||||
@@ -729,6 +753,8 @@ function switchFormMode(formId) {
|
||||
const boardMinutesContainer = document.getElementById('board-minutes-form-container');
|
||||
const quotationContainer = document.getElementById('quotation-form-container');
|
||||
const officialLetterContainer = document.getElementById('official-letter-form-container');
|
||||
const lp1Container = document.getElementById('leave-promotion-1st-form-container');
|
||||
const lp2Container = document.getElementById('leave-promotion-2nd-form-container');
|
||||
const bodyArea = document.getElementById('body-area');
|
||||
const expenseLoadBtn = document.getElementById('expense-load-btn');
|
||||
|
||||
@@ -747,6 +773,8 @@ function switchFormMode(formId) {
|
||||
boardMinutesContainer.style.display = 'none';
|
||||
quotationContainer.style.display = 'none';
|
||||
officialLetterContainer.style.display = 'none';
|
||||
lp1Container.style.display = 'none';
|
||||
lp2Container.style.display = 'none';
|
||||
expenseLoadBtn.style.display = 'none';
|
||||
bodyArea.style.display = 'none';
|
||||
isExpenseForm = false;
|
||||
@@ -761,6 +789,8 @@ function switchFormMode(formId) {
|
||||
isBoardMinutesForm = false;
|
||||
isQuotationForm = false;
|
||||
isOfficialLetterForm = false;
|
||||
isLeavePromotion1stForm = false;
|
||||
isLeavePromotion2ndForm = false;
|
||||
|
||||
if (code === 'expense') {
|
||||
isExpenseForm = true;
|
||||
@@ -835,6 +865,12 @@ function switchFormMode(formId) {
|
||||
} else if (code === 'official_letter') {
|
||||
isOfficialLetterForm = true;
|
||||
officialLetterContainer.style.display = '';
|
||||
} else if (code === 'leave_promotion_1st') {
|
||||
isLeavePromotion1stForm = true;
|
||||
lp1Container.style.display = '';
|
||||
} else if (code === 'leave_promotion_2nd') {
|
||||
isLeavePromotion2ndForm = true;
|
||||
lp2Container.style.display = '';
|
||||
} else {
|
||||
bodyArea.style.display = '';
|
||||
}
|
||||
@@ -845,7 +881,7 @@ function applyBodyTemplate(formId) {
|
||||
switchFormMode(formId);
|
||||
|
||||
// 전용 폼이면 제목을 양식명으로 설정하고 body template 적용 건너뜀
|
||||
if (isExpenseForm || isPurchaseRequestForm || isLeaveForm || isCertForm || isCareerCertForm || isAppointmentCertForm || isResignationForm || isSealUsageForm || isDelegationForm || isBoardMinutesForm || isQuotationForm || isOfficialLetterForm) {
|
||||
if (isExpenseForm || isPurchaseRequestForm || isLeaveForm || isCertForm || isCareerCertForm || isAppointmentCertForm || isResignationForm || isSealUsageForm || isDelegationForm || isBoardMinutesForm || isQuotationForm || isOfficialLetterForm || isLeavePromotion1stForm || isLeavePromotion2ndForm) {
|
||||
const titleEl = document.getElementById('title');
|
||||
const formSelect = document.getElementById('form_id');
|
||||
titleEl.value = formSelect.options[formSelect.selectedIndex].text;
|
||||
@@ -1181,6 +1217,22 @@ function applyBodyTemplate(formId) {
|
||||
email: document.getElementById('ol-email-input')?.value || document.getElementById('ol-email').value,
|
||||
};
|
||||
formBody = null;
|
||||
} else if (isLeavePromotion1stForm) {
|
||||
const lp1UserId = document.getElementById('lp1-user-id').value;
|
||||
if (!lp1UserId) { showToast('대상 직원을 선택해주세요.', 'warning'); return; }
|
||||
const lp1Deadline = document.getElementById('lp1-deadline').value;
|
||||
if (!lp1Deadline) { showToast('사용계획 제출기한을 입력해주세요.', 'warning'); return; }
|
||||
|
||||
formContent = getLp1Data();
|
||||
formBody = null;
|
||||
} else if (isLeavePromotion2ndForm) {
|
||||
const lp2UserId = document.getElementById('lp2-user-id').value;
|
||||
if (!lp2UserId) { showToast('대상 직원을 선택해주세요.', 'warning'); return; }
|
||||
const lp2Dates = getLp2Dates();
|
||||
if (lp2Dates.length === 0) { showToast('지정 휴가일을 1건 이상 입력해주세요.', 'warning'); return; }
|
||||
|
||||
formContent = getLp2Data();
|
||||
formBody = null;
|
||||
} else if (isDelegationForm) {
|
||||
const dlAgentName = document.getElementById('dl-agent-name').value.trim();
|
||||
if (!dlAgentName) {
|
||||
|
||||
@@ -168,6 +168,18 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
])
|
||||
|
||||
{{-- 연차사용촉진 1차 통지서 --}}
|
||||
@include('approvals.partials._leave-promotion-1st-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
'employees' => $employees ?? collect(),
|
||||
])
|
||||
|
||||
{{-- 연차사용촉진 2차 통지서 --}}
|
||||
@include('approvals.partials._leave-promotion-2nd-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
'employees' => $employees ?? collect(),
|
||||
])
|
||||
|
||||
{{-- 견적서 전용 폼 --}}
|
||||
@include('approvals.partials._quotation-form', [
|
||||
'tenantInfo' => $tenantInfo ?? [],
|
||||
@@ -314,6 +326,8 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm fon
|
||||
let isBoardMinutesForm = false;
|
||||
let isQuotationForm = false;
|
||||
let isOfficialLetterForm = false;
|
||||
let isLeavePromotion1stForm = false;
|
||||
let isLeavePromotion2ndForm = false;
|
||||
|
||||
const formDescriptions = {
|
||||
BUSINESS_DRAFT: {
|
||||
@@ -381,6 +395,16 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm fon
|
||||
color: 'border-slate-300 bg-slate-50', titleColor: 'text-slate-800', textColor: 'text-slate-600',
|
||||
text: '이사회 개최 내용을 기록하는 공식 문서입니다. 일시, 장소, 출석현황, 의안, 의사경과, 기명날인 등을 기재하며, 법적 효력을 갖는 회의록입니다.',
|
||||
},
|
||||
leave_promotion_1st: {
|
||||
title: '연차사용촉진 통지서 (1차)', icon: '📅',
|
||||
color: 'border-orange-200 bg-orange-50', titleColor: 'text-orange-800', textColor: 'text-orange-600',
|
||||
text: '근로기준법 제61조에 따른 연차 사용 촉진 1차 통지서입니다. 잔여 연차 현황을 안내하고, 사용계획 제출기한을 지정하여 직원에게 통보합니다.',
|
||||
},
|
||||
leave_promotion_2nd: {
|
||||
title: '연차사용촉진 통지서 (2차)', icon: '🚨',
|
||||
color: 'border-red-200 bg-red-50', titleColor: 'text-red-800', textColor: 'text-red-600',
|
||||
text: '1차 통지 후에도 사용 시기를 제출하지 않은 직원에게 회사가 휴가일을 지정하는 2차 통지서입니다. 근로기준법 제61조에 따른 법적 효력이 있습니다.',
|
||||
},
|
||||
quotation: {
|
||||
title: '견적서', icon: '💰',
|
||||
color: 'border-emerald-200 bg-emerald-50', titleColor: 'text-emerald-800', textColor: 'text-emerald-600',
|
||||
@@ -416,7 +440,7 @@ class="px-6 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg text-sm fon
|
||||
// 2단계 분류 정의
|
||||
const formCategoryMap = {
|
||||
BUSINESS_DRAFT: '일반', official_letter: '일반',
|
||||
leave: '인사/근태', attendance_request: '인사/근태', resignation: '인사/근태', reason_report: '인사/근태', delegation: '인사/근태', board_minutes: '인사/근태',
|
||||
leave: '인사/근태', attendance_request: '인사/근태', resignation: '인사/근태', reason_report: '인사/근태', delegation: '인사/근태', board_minutes: '인사/근태', leave_promotion_1st: '인사/근태', leave_promotion_2nd: '인사/근태',
|
||||
employment_cert: '증명서', career_cert: '증명서', appointment_cert: '증명서', seal_usage: '증명서',
|
||||
pr_expense: '품의', pr_contract: '품의', pr_purchase: '품의', pr_trip: '품의', pr_settlement: '품의',
|
||||
expense: '재무', quotation: '재무',
|
||||
@@ -661,6 +685,8 @@ function switchFormMode(formId) {
|
||||
const boardMinutesContainer = document.getElementById('board-minutes-form-container');
|
||||
const quotationContainer = document.getElementById('quotation-form-container');
|
||||
const officialLetterContainer = document.getElementById('official-letter-form-container');
|
||||
const lp1Container = document.getElementById('leave-promotion-1st-form-container');
|
||||
const lp2Container = document.getElementById('leave-promotion-2nd-form-container');
|
||||
const bodyArea = document.getElementById('body-area');
|
||||
|
||||
expenseContainer.style.display = 'none';
|
||||
@@ -671,6 +697,8 @@ function switchFormMode(formId) {
|
||||
boardMinutesContainer.style.display = 'none';
|
||||
quotationContainer.style.display = 'none';
|
||||
officialLetterContainer.style.display = 'none';
|
||||
lp1Container.style.display = 'none';
|
||||
lp2Container.style.display = 'none';
|
||||
bodyArea.style.display = 'none';
|
||||
isExpenseForm = false;
|
||||
isPurchaseRequestForm = false;
|
||||
@@ -680,6 +708,8 @@ function switchFormMode(formId) {
|
||||
isBoardMinutesForm = false;
|
||||
isQuotationForm = false;
|
||||
isOfficialLetterForm = false;
|
||||
isLeavePromotion1stForm = false;
|
||||
isLeavePromotion2ndForm = false;
|
||||
|
||||
if (code === 'expense') {
|
||||
isExpenseForm = true;
|
||||
@@ -711,6 +741,12 @@ function switchFormMode(formId) {
|
||||
} else if (code === 'official_letter') {
|
||||
isOfficialLetterForm = true;
|
||||
officialLetterContainer.style.display = '';
|
||||
} else if (code === 'leave_promotion_1st') {
|
||||
isLeavePromotion1stForm = true;
|
||||
lp1Container.style.display = '';
|
||||
} else if (code === 'leave_promotion_2nd') {
|
||||
isLeavePromotion2ndForm = true;
|
||||
lp2Container.style.display = '';
|
||||
} else {
|
||||
bodyArea.style.display = '';
|
||||
}
|
||||
@@ -721,7 +757,7 @@ function applyBodyTemplate(formId) {
|
||||
switchFormMode(formId);
|
||||
|
||||
// 전용 폼이면 제목만 자동 설정하고 body template 적용 건너뜀
|
||||
if (isExpenseForm || isPurchaseRequestForm || isCertForm || isSealUsageForm || isDelegationForm || isBoardMinutesForm || isQuotationForm || isOfficialLetterForm) {
|
||||
if (isExpenseForm || isPurchaseRequestForm || isCertForm || isSealUsageForm || isDelegationForm || isBoardMinutesForm || isQuotationForm || isOfficialLetterForm || isLeavePromotion1stForm || isLeavePromotion2ndForm) {
|
||||
const titleEl = document.getElementById('title');
|
||||
if (!titleEl.value.trim()) {
|
||||
const formSelect = document.getElementById('form_id');
|
||||
@@ -916,8 +952,39 @@ function applyBodyTemplate(formId) {
|
||||
}
|
||||
}
|
||||
|
||||
// 연차사용촉진 1차 통지서 기존 데이터 복원
|
||||
if (isLeavePromotion1stForm) {
|
||||
const lp1Content = @json($approval->content ?? []);
|
||||
if (lp1Content.employee_id) {
|
||||
document.getElementById('lp1-user-id').value = lp1Content.employee_id || '';
|
||||
document.getElementById('lp1-department').value = lp1Content.department || '';
|
||||
document.getElementById('lp1-position').value = lp1Content.position || '';
|
||||
document.getElementById('lp1-total-days').value = lp1Content.total_days || 0;
|
||||
document.getElementById('lp1-used-days').value = lp1Content.used_days || 0;
|
||||
document.getElementById('lp1-remaining-days').value = lp1Content.remaining_days || 0;
|
||||
document.getElementById('lp1-deadline').value = lp1Content.deadline || '';
|
||||
}
|
||||
}
|
||||
|
||||
// 연차사용촉진 2차 통지서 기존 데이터 복원
|
||||
if (isLeavePromotion2ndForm) {
|
||||
const lp2Content = @json($approval->content ?? []);
|
||||
if (lp2Content.employee_id) {
|
||||
document.getElementById('lp2-user-id').value = lp2Content.employee_id || '';
|
||||
document.getElementById('lp2-department').value = lp2Content.department || '';
|
||||
document.getElementById('lp2-position').value = lp2Content.position || '';
|
||||
document.getElementById('lp2-remaining-days').value = lp2Content.remaining_days || 0;
|
||||
if (lp2Content.designated_dates && lp2Content.designated_dates.length > 0) {
|
||||
const lp2Alpine = document.getElementById('leave-promotion-2nd-form-container')._x_dataStack?.[0];
|
||||
if (lp2Alpine) {
|
||||
lp2Alpine.dates = lp2Content.designated_dates.map(d => ({ date: d }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 전용 폼이 아닌 경우에만 Quill 편집기 자동 활성화
|
||||
if (!isExpenseForm && !isPurchaseRequestForm && !isCertForm && !isSealUsageForm && !isDelegationForm && !isBoardMinutesForm && !isQuotationForm && !isOfficialLetterForm) {
|
||||
if (!isExpenseForm && !isPurchaseRequestForm && !isCertForm && !isSealUsageForm && !isDelegationForm && !isBoardMinutesForm && !isQuotationForm && !isOfficialLetterForm && !isLeavePromotion1stForm && !isLeavePromotion2ndForm) {
|
||||
const existingBody = document.getElementById('body').value;
|
||||
if (/<[a-z][\s\S]*>/i.test(existingBody)) {
|
||||
document.getElementById('useEditor').checked = true;
|
||||
@@ -1100,6 +1167,20 @@ function applyBodyTemplate(formId) {
|
||||
email: document.getElementById('ol-email-input')?.value || document.getElementById('ol-email').value,
|
||||
};
|
||||
formBody = null;
|
||||
} else if (isLeavePromotion1stForm) {
|
||||
const lp1UserId = document.getElementById('lp1-user-id').value;
|
||||
if (!lp1UserId) { showToast('대상 직원을 선택해주세요.', 'warning'); return; }
|
||||
const lp1Deadline = document.getElementById('lp1-deadline').value;
|
||||
if (!lp1Deadline) { showToast('사용계획 제출기한을 입력해주세요.', 'warning'); return; }
|
||||
formContent = getLp1Data();
|
||||
formBody = null;
|
||||
} else if (isLeavePromotion2ndForm) {
|
||||
const lp2UserId = document.getElementById('lp2-user-id').value;
|
||||
if (!lp2UserId) { showToast('대상 직원을 선택해주세요.', 'warning'); return; }
|
||||
const lp2Dates = getLp2Dates();
|
||||
if (lp2Dates.length === 0) { showToast('지정 휴가일을 1건 이상 입력해주세요.', 'warning'); return; }
|
||||
formContent = getLp2Data();
|
||||
formBody = null;
|
||||
} else if (isDelegationForm) {
|
||||
const dlAgentName = document.getElementById('dl-agent-name').value.trim();
|
||||
if (!dlAgentName) {
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
{{--
|
||||
연차유급휴가 사용촉진 통지서 (1차) 전용 폼
|
||||
Props:
|
||||
$tenantInfo (array) - 테넌트(회사) 정보
|
||||
$employees (Collection) - 직원 목록
|
||||
--}}
|
||||
@php
|
||||
$tenantInfo = $tenantInfo ?? [];
|
||||
$employees = $employees ?? collect();
|
||||
@endphp
|
||||
|
||||
<div id="leave-promotion-1st-form-container" style="display: none;" class="mb-4">
|
||||
<input type="hidden" id="lp1-company-name" value="{{ $tenantInfo['company_name'] ?? '' }}">
|
||||
<input type="hidden" id="lp1-ceo-name" value="{{ $tenantInfo['ceo_name'] ?? '' }}">
|
||||
|
||||
<div class="space-y-4">
|
||||
{{-- 1. 수신자 정보 --}}
|
||||
<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">1. 수신자 정보</h3>
|
||||
</div>
|
||||
<div class="p-4 space-y-3">
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<div style="flex: 1 1 300px; max-width: 400px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">대상 직원 <span class="text-red-500">*</span></label>
|
||||
<select id="lp1-user-id" onchange="loadLp1EmployeeInfo(this.value)"
|
||||
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>
|
||||
@foreach($employees as $emp)
|
||||
<option value="{{ $emp->id }}"
|
||||
data-department="{{ $emp->departments->first()?->name ?? '' }}"
|
||||
data-position="{{ $emp->position ?? '' }}">
|
||||
{{ $emp->name }} {{ $emp->departments->first()?->name ? '('.$emp->departments->first()->name.')' : '' }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<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">부서</label>
|
||||
<input type="text" id="lp1-department" readonly
|
||||
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 150px; max-width: 200px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">직급</label>
|
||||
<input type="text" id="lp1-position" readonly
|
||||
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>
|
||||
|
||||
{{-- 2. 연차 현황 --}}
|
||||
<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">2. 연차 현황</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<div style="flex: 0 0 120px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">발생연차 <span class="text-red-500">*</span></label>
|
||||
<input type="number" id="lp1-total-days" min="0" step="0.5" value="15"
|
||||
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 text-center">
|
||||
</div>
|
||||
<div style="flex: 0 0 120px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">사용연차</label>
|
||||
<input type="number" id="lp1-used-days" min="0" step="0.5" value="5"
|
||||
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 text-center">
|
||||
</div>
|
||||
<div style="flex: 0 0 120px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">잔여연차</label>
|
||||
<input type="number" id="lp1-remaining-days" readonly
|
||||
class="w-full px-3 py-2 border border-gray-200 rounded-lg text-sm bg-amber-50 text-amber-800 font-semibold text-center">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 3. 사용계획 제출기한 --}}
|
||||
<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">3. 사용계획 제출기한</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div style="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="lp1-deadline"
|
||||
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>
|
||||
<p class="text-xs text-gray-400 mt-2">* 기한 내 사용 시기를 제출하지 않을 경우 회사가 연차 사용 시기를 지정할 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 4. 통지 내용 (법적 문구) --}}
|
||||
<div class="border border-blue-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-blue-50 px-4 py-2 border-b border-blue-200">
|
||||
<h3 class="text-sm font-semibold text-blue-700">4. 법적 통지 문구</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="text-xs text-gray-600 leading-relaxed space-y-2 bg-gray-50 p-3 rounded border border-gray-200">
|
||||
<p>근로기준법 제61조에 따라 귀하의 미사용 연차유급휴가 사용을 촉진하고자 아래와 같이 통지합니다.</p>
|
||||
<p>위 잔여 연차휴가에 대하여 위 기한까지 사용 시기를 지정하여 제출하여 주시기 바랍니다.</p>
|
||||
<p class="text-red-600 font-medium">기한 내 사용 시기를 제출하지 않을 경우 회사는 근로기준법 제61조에 따라 연차휴가 사용 시기를 지정할 수 있습니다.</p>
|
||||
<p>본 통지서는 연차 사용 촉진 절차에 따른 법적 통보 문서이며, 확인 시 수신 확인으로 간주됩니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 미리보기 버튼 --}}
|
||||
<div class="flex justify-end">
|
||||
<button type="button" onclick="openLp1Preview()"
|
||||
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>
|
||||
|
||||
{{-- 1차 통지서 미리보기 모달 --}}
|
||||
<div id="lp1-preview-modal" style="display: none;" class="fixed inset-0 z-50">
|
||||
<div class="absolute inset-0 bg-black/50" onclick="closeLp1Preview()"></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: 780px;">
|
||||
<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">1차 통지서 미리보기</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" onclick="printLp1Preview()"
|
||||
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="closeLp1Preview()"
|
||||
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="lp1-preview-content" style="padding: 40px 48px; font-family: 'Pretendard', 'Malgun Gothic', sans-serif;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function loadLp1EmployeeInfo(userId) {
|
||||
const sel = document.getElementById('lp1-user-id');
|
||||
const opt = sel.options[sel.selectedIndex];
|
||||
document.getElementById('lp1-department').value = opt?.dataset?.department || '';
|
||||
document.getElementById('lp1-position').value = opt?.dataset?.position || '';
|
||||
}
|
||||
|
||||
// 잔여연차 자동 계산
|
||||
['lp1-total-days', 'lp1-used-days'].forEach(id => {
|
||||
document.getElementById(id)?.addEventListener('input', function() {
|
||||
const total = parseFloat(document.getElementById('lp1-total-days').value) || 0;
|
||||
const used = parseFloat(document.getElementById('lp1-used-days').value) || 0;
|
||||
document.getElementById('lp1-remaining-days').value = Math.max(0, total - used);
|
||||
});
|
||||
});
|
||||
// 초기 계산
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const total = parseFloat(document.getElementById('lp1-total-days')?.value) || 0;
|
||||
const used = parseFloat(document.getElementById('lp1-used-days')?.value) || 0;
|
||||
const rem = document.getElementById('lp1-remaining-days');
|
||||
if (rem) rem.value = Math.max(0, total - used);
|
||||
});
|
||||
|
||||
function buildLp1PreviewHtml(data) {
|
||||
return '<div style="text-align:center;margin-bottom:32px;">' +
|
||||
'<h1 style="font-size:20px;font-weight:800;margin:0;letter-spacing:4px;">연차유급휴가 사용촉진 통지서 (1차)</h1>' +
|
||||
'</div>' +
|
||||
'<div style="border-bottom:2px solid #333;padding-bottom:12px;margin-bottom:24px;font-size:13px;line-height:2;">' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">수신</span> : ' + (data.employee_name || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">부서</span> : ' + (data.department || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">직급</span> : ' + (data.position || '') + '</div>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:24px;">' +
|
||||
'<p>근로기준법 제61조에 따라 귀하의 미사용 연차유급휴가 사용을 촉진하고자 아래와 같이 통지합니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="margin:24px 0;padding:16px 20px;border:1px solid #ddd;border-radius:4px;">' +
|
||||
'<div style="font-size:13px;font-weight:700;margin-bottom:8px;">■ 연차 현황</div>' +
|
||||
'<table style="width:100%;border-collapse:collapse;font-size:13px;">' +
|
||||
'<tr><td style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;font-weight:600;width:100px;">발생연차</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + (data.total_days || 0) + '일</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;font-weight:600;width:100px;">사용연차</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + (data.used_days || 0) + '일</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;font-weight:600;width:100px;">잔여연차</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;color:#dc2626;font-weight:700;">' + (data.remaining_days || 0) + '일</td></tr>' +
|
||||
'</table>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:16px;">' +
|
||||
'<p>위 잔여 연차휴가에 대하여 아래 기한까지 사용 시기를 지정하여 제출하여 주시기 바랍니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="margin:16px 0;padding:12px 20px;border:1px solid #ddd;border-radius:4px;background:#fffbeb;">' +
|
||||
'<div style="font-size:13px;font-weight:700;">■ 사용계획 제출기한 : ' + (data.deadline || '') + '</div>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:12px;line-height:1.8;margin:24px 0;padding:12px 16px;background:#f8f9fa;border-radius:4px;color:#666;">' +
|
||||
'<p>기한 내 사용 시기를 제출하지 않을 경우 회사는 근로기준법 제61조에 따라 연차휴가 사용 시기를 지정할 수 있습니다.</p>' +
|
||||
'<p>본 통지서는 연차 사용 촉진 절차에 따른 법적 통보 문서이며, 확인 시 수신 확인으로 간주됩니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="text-align:center;margin:40px 0 16px;font-size:14px;">' +
|
||||
'<span>' + (data.company_name || '') + '</span> ' +
|
||||
'<span>대표이사 ' + (data.ceo_name || '') + '</span> ' +
|
||||
'<span style="color:#999;">[직인날인]</span>' +
|
||||
'</div>' +
|
||||
'<div style="border-top:2px solid #333;padding-top:12px;margin-top:24px;">' +
|
||||
'<div style="font-size:12px;color:#666;text-align:center;">□ 본인은 위 내용을 확인하였으며 연차 사용 시기를 제출하겠습니다.</div>' +
|
||||
'<div style="text-align:right;margin-top:12px;font-size:12px;color:#999;">서명: ________________________ 일자: ____년 ____월 ____일</div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function getLp1Data() {
|
||||
const sel = document.getElementById('lp1-user-id');
|
||||
const opt = sel.options[sel.selectedIndex];
|
||||
return {
|
||||
employee_name: opt?.text?.replace(/\s*\(.*\)/, '') || '',
|
||||
employee_id: sel.value,
|
||||
department: document.getElementById('lp1-department').value,
|
||||
position: document.getElementById('lp1-position').value,
|
||||
total_days: parseFloat(document.getElementById('lp1-total-days').value) || 0,
|
||||
used_days: parseFloat(document.getElementById('lp1-used-days').value) || 0,
|
||||
remaining_days: parseFloat(document.getElementById('lp1-remaining-days').value) || 0,
|
||||
deadline: document.getElementById('lp1-deadline').value,
|
||||
company_name: document.getElementById('lp1-company-name').value,
|
||||
ceo_name: document.getElementById('lp1-ceo-name').value,
|
||||
};
|
||||
}
|
||||
|
||||
function openLp1Preview() {
|
||||
document.getElementById('lp1-preview-content').innerHTML = buildLp1PreviewHtml(getLp1Data());
|
||||
document.getElementById('lp1-preview-modal').style.display = '';
|
||||
}
|
||||
function closeLp1Preview() { document.getElementById('lp1-preview-modal').style.display = 'none'; }
|
||||
function printLp1Preview() {
|
||||
const content = document.getElementById('lp1-preview-content').innerHTML;
|
||||
const win = window.open('', '_blank');
|
||||
win.document.write('<html><head><title>연차사용촉진 1차 통지서</title><style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:40px 48px;}@media print{body{padding:20px 30px;}}</style></head><body>' + content + '</body></html>');
|
||||
win.document.close();
|
||||
win.print();
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,176 @@
|
||||
{{--
|
||||
연차유급휴가 사용촉진 통지서 (1차) 읽기전용
|
||||
Props:
|
||||
$content (array) - approvals.content JSON
|
||||
--}}
|
||||
<div class="space-y-4">
|
||||
{{-- 미리보기 버튼 --}}
|
||||
<div class="flex justify-end gap-2">
|
||||
<button type="button" onclick="openLp1ShowPreview()"
|
||||
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['employee_name'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">부서</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['department'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">직급</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['position'] ?? '-' }}</div>
|
||||
</div>
|
||||
</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(3, 1fr);">
|
||||
<div class="text-center p-3 bg-blue-50 rounded-lg">
|
||||
<div class="text-xs text-blue-600">발생연차</div>
|
||||
<div class="text-lg font-bold text-blue-800 mt-1">{{ $content['total_days'] ?? 0 }}일</div>
|
||||
</div>
|
||||
<div class="text-center p-3 bg-green-50 rounded-lg">
|
||||
<div class="text-xs text-green-600">사용연차</div>
|
||||
<div class="text-lg font-bold text-green-800 mt-1">{{ $content['used_days'] ?? 0 }}일</div>
|
||||
</div>
|
||||
<div class="text-center p-3 bg-amber-50 rounded-lg">
|
||||
<div class="text-xs text-amber-600">잔여연차</div>
|
||||
<div class="text-lg font-bold text-amber-800 mt-1">{{ $content['remaining_days'] ?? 0 }}일</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 사용계획 제출기한 --}}
|
||||
<div class="border border-amber-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-amber-50 px-4 py-2 border-b border-amber-200">
|
||||
<h3 class="text-sm font-semibold text-amber-700">사용계획 제출기한</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="text-base font-semibold text-amber-800">{{ $content['deadline'] ?? '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 법적 문구 --}}
|
||||
<div class="border border-blue-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-blue-50 px-4 py-2 border-b border-blue-200">
|
||||
<h3 class="text-sm font-semibold text-blue-700">법적 통지 문구</h3>
|
||||
</div>
|
||||
<div class="p-4 text-xs text-gray-600 leading-relaxed space-y-1">
|
||||
<p>근로기준법 제61조에 따라 귀하의 미사용 연차유급휴가 사용을 촉진하고자 통지합니다.</p>
|
||||
<p class="text-red-600 font-medium">기한 내 사용 시기를 제출하지 않을 경우 회사는 연차휴가 사용 시기를 지정할 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 미리보기 모달 --}}
|
||||
<div id="lp1-show-preview-modal" style="display: none;" class="fixed inset-0 z-50">
|
||||
<div class="absolute inset-0 bg-black/50" onclick="closeLp1ShowPreview()"></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: 780px;">
|
||||
<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">1차 통지서 미리보기</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" onclick="printLp1ShowPreview()"
|
||||
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="closeLp1ShowPreview()"
|
||||
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="lp1-show-preview-content" style="padding: 40px 48px; font-family: 'Pretendard', 'Malgun Gothic', sans-serif;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function buildLp1ShowPreviewHtml(data) {
|
||||
return '<div style="text-align:center;margin-bottom:32px;">' +
|
||||
'<h1 style="font-size:20px;font-weight:800;margin:0;letter-spacing:4px;">연차유급휴가 사용촉진 통지서 (1차)</h1>' +
|
||||
'</div>' +
|
||||
'<div style="border-bottom:2px solid #333;padding-bottom:12px;margin-bottom:24px;font-size:13px;line-height:2;">' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">수신</span> : ' + (data.employee_name || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">부서</span> : ' + (data.department || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">직급</span> : ' + (data.position || '') + '</div>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:24px;">' +
|
||||
'<p>근로기준법 제61조에 따라 귀하의 미사용 연차유급휴가 사용을 촉진하고자 아래와 같이 통지합니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="margin:24px 0;padding:16px 20px;border:1px solid #ddd;border-radius:4px;">' +
|
||||
'<div style="font-size:13px;font-weight:700;margin-bottom:8px;">■ 연차 현황</div>' +
|
||||
'<table style="width:100%;border-collapse:collapse;font-size:13px;">' +
|
||||
'<tr><td style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;font-weight:600;width:100px;">발생연차</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + (data.total_days || 0) + '일</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;font-weight:600;width:100px;">사용연차</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + (data.used_days || 0) + '일</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;font-weight:600;width:100px;">잔여연차</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;color:#dc2626;font-weight:700;">' + (data.remaining_days || 0) + '일</td></tr>' +
|
||||
'</table>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:16px;">' +
|
||||
'<p>위 잔여 연차휴가에 대하여 아래 기한까지 사용 시기를 지정하여 제출하여 주시기 바랍니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="margin:16px 0;padding:12px 20px;border:1px solid #ddd;border-radius:4px;background:#fffbeb;">' +
|
||||
'<div style="font-size:13px;font-weight:700;">■ 사용계획 제출기한 : ' + (data.deadline || '') + '</div>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:12px;line-height:1.8;margin:24px 0;padding:12px 16px;background:#f8f9fa;border-radius:4px;color:#666;">' +
|
||||
'<p>기한 내 사용 시기를 제출하지 않을 경우 회사는 근로기준법 제61조에 따라 연차휴가 사용 시기를 지정할 수 있습니다.</p>' +
|
||||
'<p>본 통지서는 연차 사용 촉진 절차에 따른 법적 통보 문서이며, 확인 시 수신 확인으로 간주됩니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="text-align:center;margin:40px 0 16px;font-size:14px;">' +
|
||||
'<span>' + (data.company_name || '') + '</span> ' +
|
||||
'<span>대표이사 ' + (data.ceo_name || '') + '</span> ' +
|
||||
'<span style="color:#999;">[직인날인]</span>' +
|
||||
'</div>' +
|
||||
'<div style="border-top:2px solid #333;padding-top:12px;margin-top:24px;">' +
|
||||
'<div style="font-size:12px;color:#666;text-align:center;">□ 본인은 위 내용을 확인하였으며 연차 사용 시기를 제출하겠습니다.</div>' +
|
||||
'<div style="text-align:right;margin-top:12px;font-size:12px;color:#999;">서명: ________________________ 일자: ____년 ____월 ____일</div>' +
|
||||
'</div>';
|
||||
}
|
||||
function openLp1ShowPreview() {
|
||||
const data = @json($content);
|
||||
document.getElementById('lp1-show-preview-content').innerHTML = buildLp1ShowPreviewHtml(data);
|
||||
document.getElementById('lp1-show-preview-modal').style.display = '';
|
||||
}
|
||||
function closeLp1ShowPreview() { document.getElementById('lp1-show-preview-modal').style.display = 'none'; }
|
||||
function printLp1ShowPreview() {
|
||||
const content = document.getElementById('lp1-show-preview-content').innerHTML;
|
||||
const win = window.open('', '_blank');
|
||||
win.document.write('<html><head><title>연차사용촉진 1차 통지서</title><style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:40px 48px;}@media print{body{padding:20px 30px;}}</style></head><body>' + content + '</body></html>');
|
||||
win.document.close();
|
||||
win.print();
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,254 @@
|
||||
{{--
|
||||
연차유급휴가 사용촉진 통지서 (2차) 전용 폼
|
||||
Props:
|
||||
$tenantInfo (array) - 테넌트(회사) 정보
|
||||
$employees (Collection) - 직원 목록
|
||||
--}}
|
||||
@php
|
||||
$tenantInfo = $tenantInfo ?? [];
|
||||
$employees = $employees ?? collect();
|
||||
@endphp
|
||||
|
||||
<div id="leave-promotion-2nd-form-container" style="display: none;" class="mb-4"
|
||||
x-data="{
|
||||
dates: [{ date: '' }],
|
||||
addDate() { this.dates.push({ date: '' }); },
|
||||
removeDate(i) { if (this.dates.length > 1) this.dates.splice(i, 1); },
|
||||
}">
|
||||
<input type="hidden" id="lp2-company-name" value="{{ $tenantInfo['company_name'] ?? '' }}">
|
||||
<input type="hidden" id="lp2-ceo-name" value="{{ $tenantInfo['ceo_name'] ?? '' }}">
|
||||
|
||||
<div class="space-y-4">
|
||||
{{-- 1. 수신자 정보 --}}
|
||||
<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">1. 수신자 정보</h3>
|
||||
</div>
|
||||
<div class="p-4 space-y-3">
|
||||
<div class="flex gap-4 flex-wrap">
|
||||
<div style="flex: 1 1 300px; max-width: 400px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">대상 직원 <span class="text-red-500">*</span></label>
|
||||
<select id="lp2-user-id" onchange="loadLp2EmployeeInfo(this.value)"
|
||||
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>
|
||||
@foreach($employees as $emp)
|
||||
<option value="{{ $emp->id }}"
|
||||
data-department="{{ $emp->departments->first()?->name ?? '' }}"
|
||||
data-position="{{ $emp->position ?? '' }}">
|
||||
{{ $emp->name }} {{ $emp->departments->first()?->name ? '('.$emp->departments->first()->name.')' : '' }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<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">부서</label>
|
||||
<input type="text" id="lp2-department" readonly
|
||||
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 150px; max-width: 200px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">직급</label>
|
||||
<input type="text" id="lp2-position" readonly
|
||||
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>
|
||||
|
||||
{{-- 2. 잔여 연차 --}}
|
||||
<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">2. 잔여 연차</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div style="max-width: 150px;">
|
||||
<label class="block text-xs font-medium text-gray-500 mb-1">잔여연차 <span class="text-red-500">*</span></label>
|
||||
<input type="number" id="lp2-remaining-days" min="0" step="0.5" value="10"
|
||||
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 text-center font-semibold text-amber-800 bg-amber-50">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 3. 회사 지정 휴가일 --}}
|
||||
<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">3. 회사 지정 휴가일 <span class="text-red-500">*</span></h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<template x-for="(item, index) in dates" :key="index">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<span class="text-xs text-gray-400 shrink-0" style="width: 24px;" x-text="(index+1) + '.'"></span>
|
||||
<input type="date" x-model="item.date"
|
||||
class="px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
style="width: 200px;">
|
||||
<button type="button" @click="removeDate(index)" x-show="dates.length > 1"
|
||||
class="p-1 text-red-400 hover:text-red-600 transition">
|
||||
<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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<button type="button" @click="addDate()"
|
||||
class="mt-1 text-xs text-blue-600 hover:text-blue-800 font-medium 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="M12 6v6m0 0v6m0-6h6m-6 0H6"/>
|
||||
</svg>
|
||||
휴가일 추가
|
||||
</button>
|
||||
<p class="text-xs text-gray-400 mt-2">* 잔여연차 일수만큼 지정해주세요.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 4. 통지 내용 (법적 문구) --}}
|
||||
<div class="border border-red-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-red-50 px-4 py-2 border-b border-red-200">
|
||||
<h3 class="text-sm font-semibold text-red-700">4. 법적 통지 문구</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="text-xs text-gray-600 leading-relaxed space-y-2 bg-gray-50 p-3 rounded border border-gray-200">
|
||||
<p>귀하는 연차 사용촉진 1차 통보 이후에도 연차 사용 시기를 제출하지 않아 근로기준법 제61조에 따라 회사가 다음과 같이 휴가 사용일을 지정합니다.</p>
|
||||
<p>위 지정된 날짜에 연차휴가를 사용하여 주시기 바랍니다.</p>
|
||||
<p class="text-red-600 font-medium">본 통지서는 근로기준법 제61조에 따른 연차 사용촉진 절차에 의한 통보입니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 미리보기 버튼 --}}
|
||||
<div class="flex justify-end">
|
||||
<button type="button" onclick="openLp2Preview()"
|
||||
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>
|
||||
|
||||
{{-- 2차 통지서 미리보기 모달 --}}
|
||||
<div id="lp2-preview-modal" style="display: none;" class="fixed inset-0 z-50">
|
||||
<div class="absolute inset-0 bg-black/50" onclick="closeLp2Preview()"></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: 780px;">
|
||||
<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">2차 통지서 미리보기</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" onclick="printLp2Preview()"
|
||||
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="closeLp2Preview()"
|
||||
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="lp2-preview-content" style="padding: 40px 48px; font-family: 'Pretendard', 'Malgun Gothic', sans-serif;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function loadLp2EmployeeInfo(userId) {
|
||||
const sel = document.getElementById('lp2-user-id');
|
||||
const opt = sel.options[sel.selectedIndex];
|
||||
document.getElementById('lp2-department').value = opt?.dataset?.department || '';
|
||||
document.getElementById('lp2-position').value = opt?.dataset?.position || '';
|
||||
}
|
||||
|
||||
function getLp2Dates() {
|
||||
const container = document.getElementById('leave-promotion-2nd-form-container');
|
||||
const alpine = container._x_dataStack?.[0];
|
||||
if (!alpine) return [];
|
||||
return alpine.dates.filter(d => d.date).map(d => d.date);
|
||||
}
|
||||
|
||||
function buildLp2PreviewHtml(data) {
|
||||
let datesHtml = '';
|
||||
if (data.designated_dates && data.designated_dates.length > 0) {
|
||||
datesHtml = '<table style="width:100%;border-collapse:collapse;font-size:13px;">';
|
||||
datesHtml += '<tr><th style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;width:60px;">순번</th>' +
|
||||
'<th style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;">지정 휴가일</th></tr>';
|
||||
data.designated_dates.forEach((d, i) => {
|
||||
datesHtml += '<tr><td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + (i + 1) + '</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + d + '</td></tr>';
|
||||
});
|
||||
datesHtml += '</table>';
|
||||
}
|
||||
|
||||
return '<div style="text-align:center;margin-bottom:32px;">' +
|
||||
'<h1 style="font-size:20px;font-weight:800;margin:0;letter-spacing:4px;">연차유급휴가 사용촉진 통지서 (2차)</h1>' +
|
||||
'</div>' +
|
||||
'<div style="border-bottom:2px solid #333;padding-bottom:12px;margin-bottom:24px;font-size:13px;line-height:2;">' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">수신</span> : ' + (data.employee_name || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">부서</span> : ' + (data.department || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">직급</span> : ' + (data.position || '') + '</div>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:24px;">' +
|
||||
'<p>귀하는 연차 사용촉진 1차 통보 이후에도 연차 사용 시기를 제출하지 않아 근로기준법 제61조에 따라 회사가 다음과 같이 휴가 사용일을 지정합니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="margin:24px 0;padding:16px 20px;border:1px solid #ddd;border-radius:4px;">' +
|
||||
'<div style="font-size:13px;font-weight:700;margin-bottom:8px;">■ 연차 현황 : 잔여 연차 <span style="color:#dc2626;">' + (data.remaining_days || 0) + '</span>일</div>' +
|
||||
'</div>' +
|
||||
'<div style="margin:24px 0;padding:16px 20px;border:1px solid #dc2626;border-radius:4px;background:#fef2f2;">' +
|
||||
'<div style="font-size:13px;font-weight:700;margin-bottom:12px;">■ 회사 지정 휴가일</div>' +
|
||||
datesHtml +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:16px;">' +
|
||||
'<p>위 지정된 날짜에 연차휴가를 사용하여 주시기 바랍니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:12px;line-height:1.8;margin:24px 0;padding:12px 16px;background:#f8f9fa;border-radius:4px;color:#666;">' +
|
||||
'<p>본 통지서는 근로기준법 제61조에 따른 연차 사용촉진 절차에 의한 통보입니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="text-align:center;margin:40px 0 16px;font-size:14px;">' +
|
||||
'<span>' + (data.company_name || '') + '</span> ' +
|
||||
'<span>대표이사 ' + (data.ceo_name || '') + '</span> ' +
|
||||
'<span style="color:#999;">[직인날인]</span>' +
|
||||
'</div>' +
|
||||
'<div style="border-top:2px solid #333;padding-top:12px;margin-top:24px;">' +
|
||||
'<div style="font-size:12px;color:#666;text-align:center;">□ 본인은 위 내용을 확인하였습니다.</div>' +
|
||||
'<div style="text-align:right;margin-top:12px;font-size:12px;color:#999;">서명: ________________________ 일자: ____년 ____월 ____일</div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
function getLp2Data() {
|
||||
const sel = document.getElementById('lp2-user-id');
|
||||
const opt = sel.options[sel.selectedIndex];
|
||||
return {
|
||||
employee_name: opt?.text?.replace(/\s*\(.*\)/, '') || '',
|
||||
employee_id: sel.value,
|
||||
department: document.getElementById('lp2-department').value,
|
||||
position: document.getElementById('lp2-position').value,
|
||||
remaining_days: parseFloat(document.getElementById('lp2-remaining-days').value) || 0,
|
||||
designated_dates: getLp2Dates(),
|
||||
company_name: document.getElementById('lp2-company-name').value,
|
||||
ceo_name: document.getElementById('lp2-ceo-name').value,
|
||||
};
|
||||
}
|
||||
|
||||
function openLp2Preview() {
|
||||
document.getElementById('lp2-preview-content').innerHTML = buildLp2PreviewHtml(getLp2Data());
|
||||
document.getElementById('lp2-preview-modal').style.display = '';
|
||||
}
|
||||
function closeLp2Preview() { document.getElementById('lp2-preview-modal').style.display = 'none'; }
|
||||
function printLp2Preview() {
|
||||
const content = document.getElementById('lp2-preview-content').innerHTML;
|
||||
const win = window.open('', '_blank');
|
||||
win.document.write('<html><head><title>연차사용촉진 2차 통지서</title><style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:40px 48px;}@media print{body{padding:20px 30px;}}</style></head><body>' + content + '</body></html>');
|
||||
win.document.close();
|
||||
win.print();
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,176 @@
|
||||
{{--
|
||||
연차유급휴가 사용촉진 통지서 (2차) 읽기전용
|
||||
Props:
|
||||
$content (array) - approvals.content JSON
|
||||
--}}
|
||||
<div class="space-y-4">
|
||||
{{-- 미리보기 버튼 --}}
|
||||
<div class="flex justify-end gap-2">
|
||||
<button type="button" onclick="openLp2ShowPreview()"
|
||||
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['employee_name'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">부서</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['department'] ?? '-' }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="text-xs text-gray-500">직급</span>
|
||||
<div class="text-sm font-medium mt-0.5">{{ $content['position'] ?? '-' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 잔여 연차 --}}
|
||||
<div class="border border-amber-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-amber-50 px-4 py-2 border-b border-amber-200">
|
||||
<h3 class="text-sm font-semibold text-amber-700">잔여 연차</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="text-lg font-bold text-amber-800">{{ $content['remaining_days'] ?? 0 }}일</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 회사 지정 휴가일 --}}
|
||||
@if(!empty($content['designated_dates']))
|
||||
<div class="border border-red-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-red-50 px-4 py-2 border-b border-red-200">
|
||||
<h3 class="text-sm font-semibold text-red-700">회사 지정 휴가일</h3>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<div class="space-y-1">
|
||||
@foreach($content['designated_dates'] as $i => $date)
|
||||
<div class="flex items-center gap-2 text-sm">
|
||||
<span class="text-xs text-gray-400 shrink-0" style="width: 24px;">{{ $i + 1 }}.</span>
|
||||
<span class="font-medium text-gray-800">{{ $date }}</span>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- 법적 문구 --}}
|
||||
<div class="border border-red-200 rounded-lg overflow-hidden">
|
||||
<div class="bg-red-50 px-4 py-2 border-b border-red-200">
|
||||
<h3 class="text-sm font-semibold text-red-700">법적 통지 문구</h3>
|
||||
</div>
|
||||
<div class="p-4 text-xs text-gray-600 leading-relaxed space-y-1">
|
||||
<p>귀하는 1차 통보 이후에도 연차 사용 시기를 제출하지 않아 회사가 휴가 사용일을 지정합니다.</p>
|
||||
<p class="text-red-600 font-medium">본 통지서는 근로기준법 제61조에 따른 연차 사용촉진 절차에 의한 통보입니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 미리보기 모달 --}}
|
||||
<div id="lp2-show-preview-modal" style="display: none;" class="fixed inset-0 z-50">
|
||||
<div class="absolute inset-0 bg-black/50" onclick="closeLp2ShowPreview()"></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: 780px;">
|
||||
<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">2차 통지서 미리보기</h3>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" onclick="printLp2ShowPreview()"
|
||||
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="closeLp2ShowPreview()"
|
||||
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="lp2-show-preview-content" style="padding: 40px 48px; font-family: 'Pretendard', 'Malgun Gothic', sans-serif;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function buildLp2ShowPreviewHtml(data) {
|
||||
let datesHtml = '';
|
||||
if (data.designated_dates && data.designated_dates.length > 0) {
|
||||
datesHtml = '<table style="width:100%;border-collapse:collapse;font-size:13px;">';
|
||||
datesHtml += '<tr><th style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;width:60px;">순번</th>' +
|
||||
'<th style="padding:6px 12px;border:1px solid #ddd;background:#f8f9fa;">지정 휴가일</th></tr>';
|
||||
data.designated_dates.forEach(function(d, i) {
|
||||
datesHtml += '<tr><td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + (i + 1) + '</td>' +
|
||||
'<td style="padding:6px 12px;border:1px solid #ddd;text-align:center;">' + d + '</td></tr>';
|
||||
});
|
||||
datesHtml += '</table>';
|
||||
}
|
||||
|
||||
return '<div style="text-align:center;margin-bottom:32px;">' +
|
||||
'<h1 style="font-size:20px;font-weight:800;margin:0;letter-spacing:4px;">연차유급휴가 사용촉진 통지서 (2차)</h1>' +
|
||||
'</div>' +
|
||||
'<div style="border-bottom:2px solid #333;padding-bottom:12px;margin-bottom:24px;font-size:13px;line-height:2;">' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">수신</span> : ' + (data.employee_name || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">부서</span> : ' + (data.department || '') + '</div>' +
|
||||
'<div><span style="display:inline-block;width:60px;font-weight:600;">직급</span> : ' + (data.position || '') + '</div>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:24px;">' +
|
||||
'<p>귀하는 연차 사용촉진 1차 통보 이후에도 연차 사용 시기를 제출하지 않아 근로기준법 제61조에 따라 회사가 다음과 같이 휴가 사용일을 지정합니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="margin:24px 0;padding:16px 20px;border:1px solid #ddd;border-radius:4px;">' +
|
||||
'<div style="font-size:13px;font-weight:700;margin-bottom:8px;">■ 연차 현황 : 잔여 연차 <span style="color:#dc2626;">' + (data.remaining_days || 0) + '</span>일</div>' +
|
||||
'</div>' +
|
||||
'<div style="margin:24px 0;padding:16px 20px;border:1px solid #dc2626;border-radius:4px;background:#fef2f2;">' +
|
||||
'<div style="font-size:13px;font-weight:700;margin-bottom:12px;">■ 회사 지정 휴가일</div>' +
|
||||
datesHtml +
|
||||
'</div>' +
|
||||
'<div style="font-size:13px;line-height:1.8;margin-bottom:16px;">' +
|
||||
'<p>위 지정된 날짜에 연차휴가를 사용하여 주시기 바랍니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="font-size:12px;line-height:1.8;margin:24px 0;padding:12px 16px;background:#f8f9fa;border-radius:4px;color:#666;">' +
|
||||
'<p>본 통지서는 근로기준법 제61조에 따른 연차 사용촉진 절차에 의한 통보입니다.</p>' +
|
||||
'</div>' +
|
||||
'<div style="text-align:center;margin:40px 0 16px;font-size:14px;">' +
|
||||
'<span>' + (data.company_name || '') + '</span> ' +
|
||||
'<span>대표이사 ' + (data.ceo_name || '') + '</span> ' +
|
||||
'<span style="color:#999;">[직인날인]</span>' +
|
||||
'</div>' +
|
||||
'<div style="border-top:2px solid #333;padding-top:12px;margin-top:24px;">' +
|
||||
'<div style="font-size:12px;color:#666;text-align:center;">□ 본인은 위 내용을 확인하였습니다.</div>' +
|
||||
'<div style="text-align:right;margin-top:12px;font-size:12px;color:#999;">서명: ________________________ 일자: ____년 ____월 ____일</div>' +
|
||||
'</div>';
|
||||
}
|
||||
function openLp2ShowPreview() {
|
||||
const data = @json($content);
|
||||
document.getElementById('lp2-show-preview-content').innerHTML = buildLp2ShowPreviewHtml(data);
|
||||
document.getElementById('lp2-show-preview-modal').style.display = '';
|
||||
}
|
||||
function closeLp2ShowPreview() { document.getElementById('lp2-show-preview-modal').style.display = 'none'; }
|
||||
function printLp2ShowPreview() {
|
||||
const content = document.getElementById('lp2-show-preview-content').innerHTML;
|
||||
const win = window.open('', '_blank');
|
||||
win.document.write('<html><head><title>연차사용촉진 2차 통지서</title><style>body{font-family:"Pretendard","Malgun Gothic",sans-serif;padding:40px 48px;}@media print{body{padding:20px 30px;}}</style></head><body>' + content + '</body></html>');
|
||||
win.document.close();
|
||||
win.print();
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
@@ -123,6 +123,10 @@ class="bg-gray-600 hover:bg-gray-700 text-white px-4 py-2 rounded-lg transition
|
||||
@include('approvals.partials._quotation-show', ['content' => $approval->content])
|
||||
@elseif(!empty($approval->content) && $approval->form?->code === 'official_letter')
|
||||
@include('approvals.partials._official-letter-show', ['content' => $approval->content])
|
||||
@elseif(!empty($approval->content) && $approval->form?->code === 'leave_promotion_1st')
|
||||
@include('approvals.partials._leave-promotion-1st-show', ['content' => $approval->content])
|
||||
@elseif(!empty($approval->content) && $approval->form?->code === 'leave_promotion_2nd')
|
||||
@include('approvals.partials._leave-promotion-2nd-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>') !!}
|
||||
|
||||
Reference in New Issue
Block a user