diff --git a/resources/views/approvals/create.blade.php b/resources/views/approvals/create.blade.php index c430b5cb..0581292e 100644 --- a/resources/views/approvals/create.blade.php +++ b/resources/views/approvals/create.blade.php @@ -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) { diff --git a/resources/views/approvals/edit.blade.php b/resources/views/approvals/edit.blade.php index d83ec7fb..ad0a3711 100644 --- a/resources/views/approvals/edit.blade.php +++ b/resources/views/approvals/edit.blade.php @@ -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) { diff --git a/resources/views/approvals/partials/_leave-promotion-1st-form.blade.php b/resources/views/approvals/partials/_leave-promotion-1st-form.blade.php new file mode 100644 index 00000000..3923ee31 --- /dev/null +++ b/resources/views/approvals/partials/_leave-promotion-1st-form.blade.php @@ -0,0 +1,253 @@ +{{-- + 연차유급휴가 사용촉진 통지서 (1차) 전용 폼 + Props: + $tenantInfo (array) - 테넌트(회사) 정보 + $employees (Collection) - 직원 목록 +--}} +@php + $tenantInfo = $tenantInfo ?? []; + $employees = $employees ?? collect(); +@endphp + +
+ +{{-- 1차 통지서 미리보기 모달 --}} + + +@push('scripts') + +@endpush diff --git a/resources/views/approvals/partials/_leave-promotion-1st-show.blade.php b/resources/views/approvals/partials/_leave-promotion-1st-show.blade.php new file mode 100644 index 00000000..6d814b2a --- /dev/null +++ b/resources/views/approvals/partials/_leave-promotion-1st-show.blade.php @@ -0,0 +1,176 @@ +{{-- + 연차유급휴가 사용촉진 통지서 (1차) 읽기전용 + Props: + $content (array) - approvals.content JSON +--}} +근로기준법 제61조에 따라 귀하의 미사용 연차유급휴가 사용을 촉진하고자 통지합니다.
+기한 내 사용 시기를 제출하지 않을 경우 회사는 연차휴가 사용 시기를 지정할 수 있습니다.
+귀하는 1차 통보 이후에도 연차 사용 시기를 제출하지 않아 회사가 휴가 사용일을 지정합니다.
+본 통지서는 근로기준법 제61조에 따른 연차 사용촉진 절차에 의한 통보입니다.
+