/** * =============================================================================== * FILE: modules/web_api/static/js/manual_absences.js * ROLE: Модальные окна "Мест. командир.", "Иное", живой автокомплит ФИО из 1С:ЗУП * и мгновенная синхронизация с боковой панелью SidebarManager. * =============================================================================== */ let activeAbsenceType = 'LOCAL_TRIP'; // 'LOCAL_TRIP' или 'OTHER' let reasonsCache = []; async function loadAbsenceReasons() { try { const res = await fetch('/api/v1/manual-absences/reasons'); if (res.ok) { const data = await res.json(); reasonsCache = data.reasons || []; } } catch (e) { console.error('Ошибка загрузки причин:', e); } } function openManualAbsenceModal(type) { activeAbsenceType = type; const isTrip = type === 'LOCAL_TRIP'; const titleEl = document.getElementById('manual-absence-modal-title'); const reasonBlock = document.getElementById('manual-absence-reason-block'); const reasonSelect = document.getElementById('manual-absence-reason-select'); if (titleEl) { titleEl.innerHTML = isTrip ? 'Местная командировка' : 'Иные причины отсутствия'; } if (reasonBlock && reasonSelect) { if (isTrip) { reasonBlock.classList.add('hidden'); } else { reasonBlock.classList.remove('hidden'); reasonSelect.innerHTML = reasonsCache.map(r => ``).join(''); } } // Сброс полей ввода const fioInput = document.getElementById('manual-absence-fio-input'); const deptInput = document.getElementById('manual-absence-dept'); const posInput = document.getElementById('manual-absence-pos'); const startDateInput = document.getElementById('manual-absence-start-date'); const endDateInput = document.getElementById('manual-absence-end-date'); const suggestionsBox = document.getElementById('manual-absence-suggestions'); if (fioInput) fioInput.value = ''; if (deptInput) deptInput.value = ''; if (posInput) posInput.value = ''; if (startDateInput) startDateInput.value = ''; if (suggestionsBox) { suggestionsBox.classList.add('hidden'); suggestionsBox.innerHTML = ''; } // Окончание по умолчанию — сегодняшний день if (endDateInput) { const today = new Date().toISOString().split('T')[0]; endDateInput.value = today; } loadManualAbsencesTable(); const modal = document.getElementById('manual-absence-modal'); if (modal) modal.classList.remove('hidden'); } function closeManualAbsenceModal() { const modal = document.getElementById('manual-absence-modal'); if (modal) modal.classList.add('hidden'); } // Живой автокомплит ФИО из базы zup_staff let searchTimeout = null; function setupStaffAutocomplete(inputEl, suggestionsBoxId) { const box = document.getElementById(suggestionsBoxId); if (!inputEl || !box) return; inputEl.addEventListener('input', function() { const val = this.value.trim(); clearTimeout(searchTimeout); if (val.length < 2) { box.classList.add('hidden'); box.innerHTML = ''; return; } searchTimeout = setTimeout(async () => { try { const res = await fetch(`/api/v1/manual-absences/staff-autocomplete?q=${encodeURIComponent(val)}`); if (!res.ok) return; const items = await res.json(); if (items.length === 0) { box.classList.add('hidden'); return; } box.innerHTML = items.map(it => `
${escapeHtml(it.fio)} ${escapeHtml(it.department)} · ${escapeHtml(it.position)}
`).join(''); box.classList.remove('hidden'); } catch (e) { console.error(e); } }, 200); }); } function selectStaffSuggestion(fio, dept, pos) { const fioInput = document.getElementById('manual-absence-fio-input'); const deptInput = document.getElementById('manual-absence-dept'); const posInput = document.getElementById('manual-absence-pos'); const box = document.getElementById('manual-absence-suggestions'); if (fioInput) fioInput.value = fio; if (deptInput) deptInput.value = dept; if (posInput) posInput.value = pos; if (box) box.classList.add('hidden'); } async function submitManualAbsence() { const fioInput = document.getElementById('manual-absence-fio-input'); const fio = fioInput ? fioInput.value.trim() : ''; if (!fio) { alert('Укажите ФИО сотрудника'); return; } const deptVal = document.getElementById('manual-absence-dept')?.value.trim() || ''; const posVal = document.getElementById('manual-absence-pos')?.value.trim() || ''; const startDateVal = document.getElementById('manual-absence-start-date')?.value || null; const endDateVal = document.getElementById('manual-absence-end-date')?.value || null; const reasonSelect = document.getElementById('manual-absence-reason-select'); const payload = { absence_type: activeAbsenceType, fio: fio, department: deptVal, position: posVal, date_start: startDateVal, date_end: endDateVal, reason: activeAbsenceType === 'LOCAL_TRIP' ? 'Местная командировка' : (reasonSelect ? reasonSelect.value : 'Иное') }; try { const res = await fetch('/api/v1/manual-absences/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (res.ok) { if (fioInput) fioInput.value = ''; loadManualAbsencesTable(); // Обновляем список карточек в боковой панели и закрываем окно if (window.SidebarManager && typeof SidebarManager.renderContent === 'function') { SidebarManager.renderContent(); } closeManualAbsenceModal(); } else { alert('Ошибка добавления записи'); } } catch (e) { alert('Сетевая ошибка при добавлении'); } } async function loadManualAbsencesTable() { const tableContainer = document.getElementById('manual-absences-table-body'); if (!tableContainer) return; try { const res = await fetch(`/api/v1/manual-absences/?type=${activeAbsenceType}`); if (!res.ok) return; const data = await res.json(); const items = data.items || []; if (items.length === 0) { tableContainer.innerHTML = 'Нет активных записей'; return; } tableContainer.innerHTML = items.map(it => ` ${escapeHtml(it.fio)} ${escapeHtml(it.department || '—')} ${escapeHtml(it.reason)} ${it.date_start || '—'} / ${it.date_end || '—'} `).join(''); } catch (e) { console.error(e); } } async function deleteManualAbsenceRecord(id) { if (!confirm('Удалить эту запись?')) return; try { const res = await fetch(`/api/v1/manual-absences/${id}`, { method: 'DELETE' }); if (res.ok) { loadManualAbsencesTable(); if (window.SidebarManager && typeof SidebarManager.renderContent === 'function') { SidebarManager.renderContent(); } } } catch (e) { alert('Ошибка при удалении'); } } document.addEventListener('DOMContentLoaded', () => { loadAbsenceReasons(); setupStaffAutocomplete( document.getElementById('manual-absence-fio-input'), 'manual-absence-suggestions' ); });