/* ===== Visit Request (출입 신청) ===== */ let myRequests = []; let categories = []; let workplaces = []; let purposes = []; let departments = []; /* ===== Status badge for visit requests ===== */ function vrStatusBadge(s) { const m = { pending: ['badge-amber', '대기중'], approved: ['badge-green', '승인됨'], rejected: ['badge-red', '반려됨'], training_completed: ['badge-blue', '교육완료'], checked_in: ['badge-blue', '체크인'], checked_out: ['badge-gray', '체크아웃'] }; const [cls, label] = m[s] || ['badge-gray', s]; return `${label}`; } function requestTypeBadge(t) { return t === 'internal' ? '내부' : '외부'; } /* ===== Toggle form fields based on request type ===== */ function toggleRequestType() { const isInternal = document.querySelector('input[name="requestType"]:checked')?.value === 'internal'; document.getElementById('companyField').style.display = isInternal ? 'none' : ''; document.getElementById('countField').style.display = isInternal ? 'none' : ''; document.getElementById('departmentField').style.display = isInternal ? '' : 'none'; document.getElementById('visitorNameRequired').classList.toggle('hidden', !isInternal); } /* ===== Load form data (purposes, categories, departments) ===== */ async function loadFormData() { try { const [purposeRes, categoryRes, deptRes] = await Promise.all([ api('/visit-requests/purposes/active'), api('/visit-requests/categories'), api('/visit-requests/departments') ]); purposes = purposeRes.data || []; categories = categoryRes.data || []; departments = deptRes.data || []; const purposeSelect = document.getElementById('purposeId'); purposeSelect.innerHTML = '' + purposes.map(p => ``).join(''); const categorySelect = document.getElementById('categoryId'); categorySelect.innerHTML = '' + categories.map(c => ``).join(''); const deptSelect = document.getElementById('departmentId'); deptSelect.innerHTML = '' + departments.map(d => ``).join(''); } catch (e) { showToast('폼 데이터 로드 실패: ' + e.message, 'error'); } } /* ===== Load workplaces by category ===== */ async function loadWorkplaces(categoryId) { const workplaceSelect = document.getElementById('workplaceId'); if (!categoryId) { workplaceSelect.innerHTML = ''; workplaces = []; return; } try { const res = await api('/visit-requests/workplaces?category_id=' + categoryId); workplaces = res.data || []; workplaceSelect.innerHTML = '' + workplaces.map(w => ``).join(''); } catch (e) { showToast('작업장 로드 실패: ' + e.message, 'error'); workplaceSelect.innerHTML = ''; } } /* ===== Load my requests ===== */ async function loadMyRequests() { try { const res = await api('/visit-requests/requests?requester_id=' + currentUser.id); myRequests = res.data || []; renderMyRequests(); } catch (e) { showToast('신청 목록 로드 실패: ' + e.message, 'error'); } } function renderMyRequests() { const tbody = document.getElementById('myRequestsBody'); if (!myRequests.length) { tbody.innerHTML = '신청 내역이 없습니다'; return; } tbody.innerHTML = myRequests.map(r => { const canDelete = r.status === 'pending'; const displayName = r.request_type === 'internal' ? escapeHtml(r.visitor_name || r.requester_full_name || '-') : escapeHtml(r.visitor_company); // 체크인/체크아웃 버튼 let checkBtn = ''; const canCheckIn = (r.request_type === 'internal' && r.status === 'approved') || (r.request_type === 'external' && ['approved', 'training_completed'].includes(r.status)); if (canCheckIn) { checkBtn = ``; } if (r.status === 'checked_in') { checkBtn = ``; } return ` ${requestTypeBadge(r.request_type)} ${displayName} ${r.visitor_count} ${escapeHtml(r.workplace_name || '-')} ${formatDate(r.visit_date)} ${r.visit_time ? String(r.visit_time).substring(0, 5) : '-'} ${escapeHtml(r.purpose_name || '-')} ${vrStatusBadge(r.status)} ${checkBtn} ${canDelete ? `` : ''} ${r.status === 'rejected' && r.rejection_reason ? `` : ''} `; }).join(''); } /* ===== Check-in / Check-out ===== */ async function doCheckIn(id) { if (!confirm('체크인 하시겠습니까?')) return; try { await api('/visit-requests/requests/' + id + '/check-in', { method: 'PUT', body: JSON.stringify({}) }); showToast('체크인 완료'); await loadMyRequests(); } catch (e) { showToast(e.message, 'error'); } } async function doCheckOut(id) { if (!confirm('체크아웃 하시겠습니까?')) return; try { await api('/visit-requests/requests/' + id + '/check-out', { method: 'PUT', body: JSON.stringify({}) }); showToast('체크아웃 완료'); await loadMyRequests(); } catch (e) { showToast(e.message, 'error'); } } /* ===== Submit request ===== */ async function submitRequest(e) { e.preventDefault(); const requestType = document.querySelector('input[name="requestType"]:checked')?.value || 'external'; const isInternal = requestType === 'internal'; const data = { request_type: requestType, visitor_company: isInternal ? '내부' : document.getElementById('visitorCompany').value.trim(), visitor_name: document.getElementById('visitorName').value.trim() || null, visitor_count: isInternal ? 1 : (parseInt(document.getElementById('visitorCount').value) || 1), department_id: isInternal ? (parseInt(document.getElementById('departmentId').value) || null) : null, category_id: parseInt(document.getElementById('categoryId').value) || null, workplace_id: parseInt(document.getElementById('workplaceId').value) || null, visit_date: document.getElementById('visitDate').value, visit_time: document.getElementById('visitTime').value, purpose_id: parseInt(document.getElementById('purposeId').value) || null, notes: document.getElementById('notes').value.trim() || null }; if (isInternal) { if (!data.visitor_name) { showToast('방문자 이름을 입력해주세요', 'error'); return; } } else { if (!data.visitor_company) { showToast('업체명을 입력해주세요', 'error'); return; } } if (!data.category_id) { showToast('작업장 분류를 선택해주세요', 'error'); return; } if (!data.workplace_id) { showToast('작업장을 선택해주세요', 'error'); return; } if (!data.visit_date) { showToast('방문일을 선택해주세요', 'error'); return; } if (!data.visit_time) { showToast('방문시간을 입력해주세요', 'error'); return; } if (!data.purpose_id) { showToast('방문 목적을 선택해주세요', 'error'); return; } try { await api('/visit-requests/requests', { method: 'POST', body: JSON.stringify(data) }); showToast(isInternal ? '내부 출입 신고가 완료되었습니다' : '출입 신청이 완료되었습니다'); document.getElementById('visitRequestForm').reset(); document.getElementById('workplaceId').innerHTML = ''; document.getElementById('visitorCount').value = '1'; toggleRequestType(); await loadMyRequests(); } catch (e) { showToast(e.message, 'error'); } } /* ===== Delete request ===== */ async function deleteRequest(id) { if (!confirm('이 신청을 삭제하시겠습니까?')) return; try { await api('/visit-requests/requests/' + id, { method: 'DELETE' }); showToast('삭제되었습니다'); await loadMyRequests(); } catch (e) { showToast(e.message, 'error'); } } /* ===== Init ===== */ function initVisitRequestPage() { if (!initAuth()) return; // Set default visit date to today const today = new Date().toISOString().substring(0, 10); document.getElementById('visitDate').value = today; // Request type toggle document.querySelectorAll('input[name="requestType"]').forEach(r => { r.addEventListener('change', toggleRequestType); }); toggleRequestType(); // Category change -> load workplaces document.getElementById('categoryId').addEventListener('change', function() { loadWorkplaces(this.value); }); document.getElementById('visitRequestForm').addEventListener('submit', submitRequest); loadFormData(); loadMyRequests(); }