function itTabSwitch(tab) { document.querySelectorAll('.it-panel').forEach(function (panel) { panel.style.display = panel.id === 'it-panel-' + tab ? '' : 'none'; }); document.querySelectorAll('.it-tab-btn').forEach(function (btn) { var active = btn.getAttribute('data-tab') === tab; btn.classList.toggle('it-tab-active', active); btn.style.background = active ? 'var(--color-card)' : 'transparent'; btn.style.color = active ? 'var(--color-card-foreground)' : 'var(--color-muted-foreground)'; btn.style.boxShadow = active ? '0 1px 2px rgb(0 0 0/0.08)' : ''; }); } function itToggleRow(key) { var row = document.getElementById('it-row-' + key); var toggle = document.getElementById('it-toggle-' + key); if (!row) return; var opening = row.style.display === 'none'; row.style.display = opening ? 'table-row' : 'none'; if (toggle) toggle.style.transform = opening ? 'rotate(90deg)' : ''; } function itIsModal(panel) { return panel && panel.getAttribute('role') === 'dialog'; } function itPanelOpen(id) { var panel = document.getElementById(id); if (!panel) return; if (itIsModal(panel)) { panel.style.display = 'flex'; document.body.style.overflow = 'hidden'; if (typeof initSearchableSelects === 'function') initSearchableSelects(panel); return; } var overlay = document.getElementById(id + '-overlay'); if (overlay) overlay.style.display = 'block'; panel.style.transform = 'translateX(0)'; document.body.style.overflow = 'hidden'; } function itPanelClose(id) { var panel = document.getElementById(id); if (!panel) return; if (itIsModal(panel)) { panel.style.display = 'none'; document.body.style.overflow = ''; return; } var overlay = document.getElementById(id + '-overlay'); if (overlay) overlay.style.display = 'none'; panel.style.transform = 'translateX(100%)'; document.body.style.overflow = ''; } var IT_EQ_DRAFT_KEY = 'it-equipment-draft'; function itEquipmentDraftSave() { var form = document.querySelector('#it-equipment-panel form'); if (!form || !window.sessionStorage) return; var data = {}; form.querySelectorAll('input, textarea, select').forEach(function (el) { if (!el.name || el.name === 'csrfmiddlewaretoken') return; if (el.type === 'checkbox' || el.type === 'radio') { data[el.name] = el.checked ? (el.value || '1') : ''; data['__checked__' + el.name] = el.checked; } else { data[el.name] = el.value; } }); try { sessionStorage.setItem(IT_EQ_DRAFT_KEY, JSON.stringify(data)); } catch (e) {} } function itEquipmentDraftRestore() { if (!window.sessionStorage) return; var raw; try { raw = sessionStorage.getItem(IT_EQ_DRAFT_KEY); } catch (e) { return; } if (!raw) return; var data; try { data = JSON.parse(raw); } catch (e) { return; } var form = document.querySelector('#it-equipment-panel form'); if (!form) return; Object.keys(data).forEach(function (name) { if (name.indexOf('__checked__') === 0) return; var el = form.querySelector('[name="' + name + '"]'); if (!el) return; if (el.type === 'checkbox' || el.type === 'radio') { el.checked = !!data['__checked__' + name]; } else { el.value = data[name] || ''; if (el.tagName === 'SELECT') { el.dispatchEvent(new Event('change', { bubbles: true })); } } }); var model = document.getElementById('it-equipment-model-select'); if (model && model.value && typeof itSetSearchableSelectValue === 'function') { itSetSearchableSelectValue('it-equipment-model-select', model.value); } } function itEquipmentDraftClear() { try { sessionStorage.removeItem(IT_EQ_DRAFT_KEY); } catch (e) {} } function itModelsOpenCatalog() { var ret = document.getElementById('it-models-return-to'); if (ret) ret.value = ''; itPanelOpen('it-equipment-models-panel'); } function itModelsOpenFromEquipment() { itEquipmentDraftSave(); var ret = document.getElementById('it-models-return-to'); if (ret) ret.value = 'equipment'; itPanelClose('it-equipment-panel'); itPanelOpen('it-equipment-models-panel'); } function itModelsDismiss() { var ret = document.getElementById('it-models-return-to'); var back = ret && ret.value === 'equipment'; itPanelClose('it-equipment-models-panel'); if (back) { itPanelOpen('it-equipment-panel'); itEquipmentDraftRestore(); } } function itModalsInit(root) { if (!root) return; if (root.getAttribute('data-it-models-open') === '1') { itPanelOpen('it-equipment-models-panel'); return; } if (root.getAttribute('data-it-equipment-open') === '1') { itPanelOpen('it-equipment-panel'); itEquipmentDraftRestore(); var mid = root.getAttribute('data-it-select-model-id'); if (mid) itSetSearchableSelectValue('it-equipment-model-select', mid); itEquipmentDraftClear(); } if (root.getAttribute('data-it-worklog-open') === '1') itPanelOpen('it-worklog-panel'); } function itContractServiceToggle(serviceTypeCode) { var block = document.getElementById('it-contract-ip-block'); if (!block) return; var show = serviceTypeCode === 'internet'; block.style.display = show ? '' : 'none'; if (!show) { var checkbox = block.querySelector('input[name=dedicated_ip]'); var ipField = document.getElementById('it-contract-ip-field'); if (checkbox) checkbox.checked = false; if (ipField) ipField.style.display = 'none'; } } function itContractFrameworkToggle(isFramework) { var parentWrap = document.getElementById('it-contract-parent-wrap'); var locationWrap = document.getElementById('it-contract-location-wrap'); var locationSelect = document.getElementById('it-contract-location-select'); var locationRequired = document.getElementById('it-contract-location-required'); if (parentWrap) { parentWrap.style.display = isFramework ? 'none' : ''; } if (isFramework) { var sel = document.getElementById('it-contract-parent-select'); if (sel) sel.value = ''; } if (locationWrap) { locationWrap.style.display = isFramework ? 'none' : ''; } if (locationSelect) { locationSelect.required = !isFramework; if (isFramework) locationSelect.value = ''; } if (locationRequired) { locationRequired.style.display = isFramework ? 'none' : ''; } } function itContractFilterParents() { var providerSelect = document.getElementById('it-contract-provider-select'); var parentSelect = document.getElementById('it-contract-parent-select'); if (!providerSelect || !parentSelect) return; var providerId = providerSelect.value; Array.prototype.forEach.call(parentSelect.options, function (opt) { if (!opt.value) { opt.hidden = false; return; } opt.hidden = providerId && opt.getAttribute('data-provider') !== providerId; }); if (parentSelect.selectedOptions[0] && parentSelect.selectedOptions[0].hidden) { parentSelect.value = ''; } } // --- Масовий вибір екземплярів обладнання --- // --- Выдача оборудования: тип → список --- function itAssignTargetChanged(selectEl) { var root = selectEl.closest('[data-assign-widget]'); if (!root) return; var target = selectEl.value || ''; root.querySelectorAll('[data-assign-pick]').forEach(function (pick) { var match = pick.getAttribute('data-assign-pick') === target; pick.style.display = match ? '' : 'none'; pick.querySelectorAll('select').forEach(function (inp) { inp.disabled = !match; if (!match) { inp.value = ''; // searchable-select слушает change inp.dispatchEvent(new Event('change', { bubbles: true })); } }); }); } function itBulkToggleAll(headerCheckbox) { document.querySelectorAll('.it-equip-check').forEach(function (cb) { cb.checked = headerCheckbox.checked; }); itBulkUpdate(); } function itBulkUpdate() { var checked = Array.prototype.slice.call(document.querySelectorAll('.it-equip-check:checked')); var panel = document.getElementById('it-equipment-bulk-assign'); var countEl = document.getElementById('it-bulk-assign-count'); var inputs = document.getElementById('it-bulk-assign-inputs'); if (!panel) return; if (checked.length) { panel.style.display = 'block'; if (countEl) countEl.textContent = checked.length; if (inputs) { // переносимо id відмічених у hidden-поля всередині форми видачі inputs.innerHTML = ''; checked.forEach(function (cb) { var hidden = document.createElement('input'); hidden.type = 'hidden'; hidden.name = 'equipment_ids'; hidden.value = cb.value; inputs.appendChild(hidden); }); } } else { panel.style.display = 'none'; } } function itBulkClearSelection() { document.querySelectorAll('.it-equip-check').forEach(function (cb) { cb.checked = false; }); var headerAll = document.querySelector('th input[onclick^="itBulkToggleAll"]'); if (headerAll) headerAll.checked = false; itBulkUpdate(); } function itEquipmentOpenLabels() { var checked = Array.prototype.slice.call(document.querySelectorAll('.it-equip-check:checked')); if (!checked.length) return; var ids = checked.map(function (cb) { return cb.value; }); // Печать строго по сохранённому шаблону (все блоки из layout) var url = '/it-manager/equipment/labels/?ids=' + encodeURIComponent(ids.join(',')); window.open(url, '_blank', 'noopener'); } /** EAN-13 check digit + тело 200 + pk(9) — как на сервере. */ function itEquipmentEan13(pk) { var body = '200' + String(pk).padStart(9, '0'); var sum = 0; for (var i = 0; i < 12; i++) { var d = parseInt(body.charAt(i), 10); sum += (i % 2 === 0) ? d : d * 3; } var check = (10 - (sum % 10)) % 10; return body + String(check); } function itFillInventoryEan(btn, pk) { var input = document.getElementById('it-inv-' + pk); var flag = document.getElementById('it-auto-inv-' + pk); if (!input) return; input.value = itEquipmentEan13(pk); if (flag) flag.value = '1'; input.focus(); } function itSetSearchableSelectValue(selectId, value) { var select = document.getElementById(selectId); if (!select) return; select.value = value || ''; select.dispatchEvent(new Event('change', { bubbles: true })); var widget = select.closest('.searchable-select'); if (widget && widget._search) { var opt = select.options[select.selectedIndex]; widget._search.value = (opt && opt.value) ? opt.textContent : ''; if (typeof widget._updateClear === 'function') widget._updateClear(); else if (widget._clear) widget._clear.style.display = select.value ? 'flex' : 'none'; } } function itWorkCatalogData() { var el = document.getElementById('it-work-catalog-data'); if (!el) return { categories: [], works: [], detail_labels: {} }; try { return JSON.parse(el.textContent || '{}'); } catch (e) { return { categories: [], works: [], detail_labels: {} }; } } function itWorklogCategoryChanged() { var cat = document.getElementById('it-worklog-category'); var work = document.getElementById('it-worklog-work'); if (!work) return; var catId = cat ? cat.value : ''; var data = itWorkCatalogData(); var works = (data.works || []).filter(function (w) { return !catId || String(w.category_id) === String(catId); }); work.innerHTML = ''; var empty = document.createElement('option'); empty.value = ''; empty.textContent = catId ? '— Выберите работу —' : '— Сначала выберите категорию —'; work.appendChild(empty); works.forEach(function (w) { var opt = document.createElement('option'); opt.value = String(w.id); opt.textContent = w.name; work.appendChild(opt); }); itWorklogWorkChanged(); } function itWorklogWorkChanged() { var workSelect = document.getElementById('it-worklog-work'); var detailsBox = document.getElementById('it-worklog-details'); var notesEl = document.getElementById('it-worklog-work-notes'); if (!detailsBox) return; var data = itWorkCatalogData(); var labels = data.detail_labels || {}; var workId = workSelect ? workSelect.value : ''; var work = (data.works || []).find(function (w) { return String(w.id) === String(workId); }); detailsBox.innerHTML = ''; if (!work || !(work.required_details || []).length) { detailsBox.style.display = 'none'; } else { detailsBox.style.display = 'flex'; (work.required_details || []).forEach(function (key) { var wrap = document.createElement('div'); var label = document.createElement('label'); label.style.cssText = 'display:block;font-size:0.8125rem;font-weight:500;color:var(--color-foreground);margin-bottom:0.375rem;'; label.textContent = labels[key] || key; var star = document.createElement('span'); star.style.color = 'var(--color-destructive)'; star.textContent = ' *'; label.appendChild(star); var input = document.createElement('input'); input.type = 'text'; input.name = 'detail_' + key; input.required = true; input.className = 'input'; input.style.width = '100%'; wrap.appendChild(label); wrap.appendChild(input); detailsBox.appendChild(wrap); }); } if (notesEl) { if (work && work.notes) { notesEl.style.display = ''; notesEl.textContent = work.notes; } else { notesEl.style.display = 'none'; notesEl.textContent = ''; } } } function itWorklogRowCategoryChanged(logPk) { var cat = document.getElementById('it-worklog-row-cat-' + logPk); var work = document.getElementById('it-worklog-row-work-' + logPk); if (!work) return; var catId = cat ? cat.value : ''; var data = itWorkCatalogData(); var works = (data.works || []).filter(function (w) { return catId && String(w.category_id) === String(catId); }); work.innerHTML = ''; var empty = document.createElement('option'); empty.value = ''; empty.textContent = catId ? '— Выберите работу —' : '—'; work.appendChild(empty); works.forEach(function (w) { var opt = document.createElement('option'); opt.value = String(w.id); opt.textContent = w.name; work.appendChild(opt); }); itWorklogRowWorkChanged(logPk, false); } function itWorklogRowWorkChanged(logPk, submit) { var workSelect = document.getElementById('it-worklog-row-work-' + logPk); var detailsBox = document.getElementById('it-worklog-row-details-' + logPk); if (!detailsBox || !workSelect) return; var data = itWorkCatalogData(); var labels = data.detail_labels || {}; var workId = workSelect.value; var work = (data.works || []).find(function (w) { return String(w.id) === String(workId); }); var formId = 'worklog-form-' + logPk; detailsBox.innerHTML = ''; if (work && (work.required_details || []).length) { (work.required_details || []).forEach(function (key) { var label = document.createElement('label'); label.style.cssText = 'font-size:0.6875rem;color:var(--color-muted-foreground);'; label.textContent = (labels[key] || key) + ' '; var input = document.createElement('input'); input.type = 'text'; input.name = 'detail_' + key; input.setAttribute('form', formId); input.className = 'input'; input.style.cssText = 'width:100%;font-size:0.75rem;padding:0.2rem 0.35rem;margin-top:0.1rem;'; input.onchange = function () { if (input.form) input.form.requestSubmit(); }; label.appendChild(document.createElement('br')); label.appendChild(input); detailsBox.appendChild(label); }); } if (submit && workId && workSelect.form) { workSelect.form.requestSubmit(); } } function itWorklogFromTicket(ticket) { if (!ticket || !ticket.id) return; itTabSwitch('worklog'); itPanelOpen('it-worklog-panel'); itSetSearchableSelectValue('it-worklog-ticket', String(ticket.id)); if (ticket.locationId) { itSetSearchableSelectValue('it-worklog-location', String(ticket.locationId)); } var equipment = document.getElementById('it-worklog-equipment'); if (equipment && ticket.equipmentId) { equipment.value = String(ticket.equipmentId); } var description = document.getElementById('it-worklog-description'); if (description && !description.value) { description.value = 'Работа по заявке ' + ticket.number + (ticket.title ? ': ' + ticket.title : ''); } var hint = document.getElementById('it-worklog-ticket-hint'); if (hint) { hint.style.display = ''; hint.textContent = 'Заявка ' + ticket.number + (ticket.title ? ' — ' + ticket.title : ''); } var catSelect = document.getElementById('it-worklog-category'); if (catSelect) catSelect.focus(); } function itWorklogTicketChanged() { var select = document.getElementById('it-worklog-ticket'); if (!select) return; var opt = select.options[select.selectedIndex]; var hint = document.getElementById('it-worklog-ticket-hint'); if (!opt || !opt.value) { if (hint) { hint.style.display = 'none'; hint.textContent = ''; } return; } var locationId = opt.getAttribute('data-location') || ''; var equipmentId = opt.getAttribute('data-equipment') || ''; if (locationId) itSetSearchableSelectValue('it-worklog-location', locationId); var equipment = document.getElementById('it-worklog-equipment'); if (equipment && equipmentId) equipment.value = equipmentId; if (hint) { hint.style.display = ''; hint.textContent = opt.textContent.trim(); } } document.addEventListener('change', function (ev) { if (ev.target && ev.target.id === 'it-worklog-ticket') { itWorklogTicketChanged(); } }); function itReportPreviewOpen(url, title) { var overlay = document.getElementById('it-report-preview-overlay'); var modal = document.getElementById('it-report-preview-modal'); var frame = document.getElementById('it-report-preview-frame'); var subtitle = document.getElementById('it-report-preview-subtitle'); var openTab = document.getElementById('it-report-preview-open-tab'); if (!overlay || !modal || !frame) return; if (subtitle) subtitle.textContent = title || ''; if (openTab) openTab.href = url; frame.src = url; overlay.style.display = 'block'; modal.style.display = 'flex'; document.body.style.overflow = 'hidden'; } function itReportPreviewClose() { var overlay = document.getElementById('it-report-preview-overlay'); var modal = document.getElementById('it-report-preview-modal'); var frame = document.getElementById('it-report-preview-frame'); if (overlay) overlay.style.display = 'none'; if (modal) modal.style.display = 'none'; if (frame) frame.src = 'about:blank'; document.body.style.overflow = ''; } document.addEventListener('keydown', function (ev) { if (ev.key !== 'Escape') return; var preview = document.getElementById('it-report-preview-modal'); if (preview && preview.style.display === 'flex') { itReportPreviewClose(); return; } var models = document.getElementById('it-equipment-models-panel'); if (models && models.style.display === 'flex') { itModelsDismiss(); return; } document.querySelectorAll('[id^="it-"][role="dialog"]').forEach(function (el) { if (el.id === 'it-equipment-models-panel' || el.id === 'it-report-preview-modal') return; if (el.style.display === 'flex') itPanelClose(el.id); }); }); function itPageAfterLoad(scope) { var root = (scope || document).querySelector('[data-it-active-tab]'); if (!root) return; if (typeof itTabSwitch === 'function') { itTabSwitch(root.getAttribute('data-it-active-tab') || 'equipment'); } if (typeof initSearchableSelects === 'function') { initSearchableSelects(scope || document); } itModalsInit(root); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', function () { itPageAfterLoad(document); }); } else { itPageAfterLoad(document); } document.addEventListener('htmx:afterSwap', function (ev) { var target = ev.detail && ev.detail.target; if (!target || target.id !== 'main-content') return; itPageAfterLoad(target); });