/* ===== 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();
}