Files
ACORE/templates/pages/it-manager.html
T
lokses 38747a93fc IT-менеджер: каталог моделей оборудования + перевод choices на справочники
- EquipmentModel (каталог: тип+бренд+модель заводятся раз) отделён от
  Equipment (экземпляр: серийник+локация); миграция сворачивает данные.
  Массовый ввод серийников, массовая выдача на локации/сотрудников
- Enum-choices (тип/статус/приоритет заявок, вид работ, каналы, расходники,
  договоры) переведены на core.Directory с quick-add из формы
- Фронт-страница /it-manager/: вкладки оборудование/заявки/работы/
  расходники/провайдеры/обращения; searchable-select локаций
- Тесты (10)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 17:31:52 +03:00

1132 lines
99 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% load common_tags %}
<div class="page-content">
<div style="margin-bottom:1.5rem;">
<h1 style="font-size:1.25rem; font-weight:500; color:var(--color-foreground);">IT-відділ</h1>
<p style="font-size:0.875rem; color:var(--color-muted-foreground); margin-top:0.25rem;">Інвентаризація обладнання, черга заявок та журнал виконаних робіт</p>
</div>
<!-- Вкладки -->
<div style="display:flex; gap:0.25rem; background:var(--color-muted); border-radius:var(--radius); padding:0.25rem; width:fit-content; margin-bottom:1.5rem;">
<button type="button" class="it-tab-btn it-tab-active" data-tab="equipment" onclick="itTabSwitch('equipment')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer; background:var(--color-card); color:var(--color-card-foreground); box-shadow:0 1px 2px rgb(0 0 0/0.08);">Обладнання</button>
<button type="button" class="it-tab-btn" data-tab="tickets" onclick="itTabSwitch('tickets')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer; background:transparent; color:var(--color-muted-foreground);">Заявки</button>
<button type="button" class="it-tab-btn" data-tab="worklog" onclick="itTabSwitch('worklog')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer; background:transparent; color:var(--color-muted-foreground);">Виконані роботи</button>
<button type="button" class="it-tab-btn" data-tab="consumables" onclick="itTabSwitch('consumables')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer; background:transparent; color:var(--color-muted-foreground);">Витратні матеріали</button>
<button type="button" class="it-tab-btn" data-tab="providers" onclick="itTabSwitch('providers')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer; background:transparent; color:var(--color-muted-foreground);">Провайдери</button>
<button type="button" class="it-tab-btn" data-tab="servicecalls" onclick="itTabSwitch('servicecalls')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer; background:transparent; color:var(--color-muted-foreground);">Обращення</button>
</div>
<!-- ══ ВКЛАДКА: ОБЛАДНАННЯ ══ -->
<div id="it-panel-equipment" class="it-panel">
<div style="display:grid; grid-template-columns:repeat(4, minmax(0,1fr)); gap:0.75rem; margin-bottom:1.5rem;">
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Всього одиниць</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_list|length }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">На складі</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_counts.stock }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Видано</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_counts.assigned }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">В ремонті / списано</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_counts.repair|add:equipment_counts.written_off }}</div>
</div>
</div>
{% if equipment_form_message %}
<div style="background:rgba(22,163,74,0.08); border:1px solid rgba(22,163,74,0.3); border-radius:0.75rem; padding:0.75rem 1rem; margin-bottom:1rem; font-size:0.875rem; color:#16a34a;">{{ equipment_form_message }}</div>
{% endif %}
{% if equipment_form_error %}
<div style="background:color-mix(in srgb, var(--color-destructive) 8%, transparent); border:1px solid color-mix(in srgb, var(--color-destructive) 30%, transparent); border-radius:0.75rem; padding:0.75rem 1rem; margin-bottom:1rem; font-size:0.875rem; color:var(--color-destructive);">{{ equipment_form_error }}</div>
{% endif %}
<div style="display:flex; justify-content:flex-end; gap:0.5rem; margin-bottom:1rem;">
<button type="button" class="btn btn-secondary" style="border:1px solid var(--color-border);" onclick="itPanelOpen('it-equipment-models-panel')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/></svg>
Каталог моделей ({{ equipment_models|length }})
</button>
<button type="button" class="btn btn-primary" onclick="itPanelOpen('it-equipment-panel')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
</svg>
Додати екземпляри
</button>
</div>
<!-- Виїзна панель: масовий ввід екземплярів -->
<div id="it-equipment-panel-overlay" onclick="itPanelClose('it-equipment-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div>
<div id="it-equipment-panel" style="position:fixed; top:0; right:0; height:100vh; width:28rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;">
<form hx-post="/it-manager/equipment/bulk-create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">Додати екземпляри</span>
<button type="button" onclick="itPanelClose('it-equipment-panel')" class="btn btn-ghost btn-icon" aria-label="Закрити">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Модель з каталогу <span style="color:var(--color-destructive);">*</span></label>
<div class="searchable-select" data-placeholder="Пошук моделі за назвою чи брендом...">
<select name="equipment_model_id" required hidden>
<option value="">—</option>
{% for m in equipment_models %}
<option value="{{ m.id }}">{{ m.equipment_type.name }} · {{ m }}</option>
{% endfor %}
</select>
</div>
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.375rem;">Немає потрібної? <a href="#" onclick="itPanelClose('it-equipment-panel'); itPanelOpen('it-equipment-models-panel'); return false;" style="color:var(--color-primary);">Додати модель у каталог</a></div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Серійні номери <span style="color:var(--color-destructive);">*</span></label>
<textarea name="serial_numbers" required placeholder="По одному в рядку — вставте список серійників, наприклад&#10;HGC09SJD200&#10;HGC09VB5ZKX&#10;HGC09VT0P2H"
style="width:100%; min-height:8rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-mono, monospace); outline:none; box-sizing:border-box;"></textarea>
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.375rem;">Скільки серійників — стільки одиниць буде створено. Дублікати й вже наявні пропускаються.</div>
</div>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:0.75rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Дата покупки</label>
<input type="date" name="purchase_date" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Гарантія до</label>
<input type="date" name="warranty_until" class="input" style="width:100%;">
</div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Одразу видати на локацію <span style="font-weight:400; color:var(--color-muted-foreground);">(необов'язково)</span></label>
<div class="searchable-select" data-placeholder="Пошук за адресою чи номером аптеки...">
<select name="location_id" hidden>
<option value="">— на склад</option>
{% for location in it_locations %}
<option value="{{ location.id }}">{{ location }}</option>
{% endfor %}
</select>
</div>
</div>
<div style="display:flex; gap:0.5rem;">
<button type="submit" class="btn btn-primary" style="flex:1;">
Створити екземпляри
<span class="btn-label-loading htmx-indicator">Збереження…</span>
</button>
<button type="button" class="btn btn-secondary" style="border:1px solid var(--color-border);" onclick="itPanelClose('it-equipment-panel')">Скасувати</button>
</div>
</div>
</form>
</div>
<!-- Виїзна панель: каталог моделей -->
<div id="it-equipment-models-panel-overlay" onclick="itPanelClose('it-equipment-models-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div>
<div id="it-equipment-models-panel" style="position:fixed; top:0; right:0; height:100vh; width:28rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;">
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">Каталог моделей</span>
<button type="button" onclick="itPanelClose('it-equipment-models-panel')" class="btn btn-ghost btn-icon" aria-label="Закрити">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<form hx-post="/it-manager/equipment/models/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"
style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem; border-bottom:1px solid var(--color-border);">
{% csrf_token %}
<div style="font-size:0.8125rem; font-weight:600; color:var(--color-foreground);">Нова модель</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Тип <span style="color:var(--color-destructive);">*</span></label>
<select name="equipment_type" required class="input" style="width:100%;" onchange="dqaHandleChange(this, 'equipment_type', 'code')">
{% for value, label in equipment_types %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
<option value="__new__">+ Додати новий тип...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Бренд</label>
<select name="brand_id" class="input" style="width:100%;" onchange="dqaHandleChange(this, 'equipment_brand', 'id')">
<option value="">—</option>
{% for brand in equipment_brands %}
<option value="{{ brand.id }}">{{ brand.name }}</option>
{% endfor %}
<option value="__new__">+ Додати новий бренд...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Модель <span style="color:var(--color-destructive);">*</span></label>
<input type="text" name="name" required placeholder="Наприклад: RB952Ui-5ac2nD" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Гарантія (міс.) <span style="font-weight:400; color:var(--color-muted-foreground);">(необов'язково)</span></label>
<input type="number" min="0" name="warranty_months" class="input" style="width:100%;">
</div>
<button type="submit" class="btn btn-primary" style="width:100%;">
Додати модель
<span class="btn-label-loading htmx-indicator">Збереження…</span>
</button>
</form>
<div style="padding:1rem 1.25rem;">
<div style="font-size:0.8125rem; font-weight:600; color:var(--color-foreground); margin-bottom:0.75rem;">У каталозі ({{ equipment_models|length }})</div>
<div style="display:flex; flex-direction:column; gap:0.5rem;">
{% for m in equipment_models %}
<div style="display:flex; align-items:center; justify-content:space-between; gap:0.5rem; padding:0.5rem 0.75rem; background:var(--color-muted); border-radius:var(--radius);">
<div style="min-width:0;">
<div style="font-size:0.8125rem; color:var(--color-foreground); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">{{ m }}</div>
<div style="font-size:0.6875rem; color:var(--color-muted-foreground);">{{ m.equipment_type.name }}</div>
</div>
<span class="badge badge-muted" style="flex-shrink:0;">{{ m.units_total }} од.</span>
</div>
{% empty %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">Каталог порожній — додайте першу модель.</div>
{% endfor %}
</div>
</div>
</div>
<!-- Панель масової видачі (з'являється при виборі екземплярів) -->
<div id="it-equipment-bulk-assign" style="display:none; background:var(--color-card); border:1px solid var(--color-primary); border-radius:0.75rem; padding:1rem 1.25rem; margin-bottom:1rem;">
<form hx-post="/it-manager/equipment/bulk-assign/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"
style="display:flex; align-items:flex-end; gap:0.75rem; flex-wrap:wrap;">
{% csrf_token %}
<div id="it-bulk-assign-inputs"></div>
<div style="font-size:0.875rem; color:var(--color-foreground); font-weight:500; align-self:center;">Видати <span id="it-bulk-assign-count">0</span> од.:</div>
<div style="min-width:16rem; flex:1;">
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">На локацію</label>
<div class="searchable-select" data-placeholder="Пошук за адресою чи номером аптеки...">
<select name="location_id" hidden>
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}">{{ location }}</option>
{% endfor %}
</select>
</div>
</div>
<div style="min-width:12rem;">
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Співробітнику</label>
<select name="assigned_to_id" class="input" style="width:100%;">
<option value="">—</option>
{% for emp in it_employees %}
<option value="{{ emp.id }}">{{ emp.last_name }} {{ emp.first_name }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">Видати</button>
<button type="button" class="btn btn-ghost" onclick="itBulkClearSelection()">Скасувати вибір</button>
</form>
</div>
<!-- Список обладнання -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
<thead>
<tr style="border-bottom:1px solid var(--color-border);">
<th style="width:2.25rem; text-align:center;"><input type="checkbox" onclick="itBulkToggleAll(this)" title="Виділити всі на сторінці" style="cursor:pointer;"></th>
<th style="width:2rem;"></th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Тип / Бренд / Модель</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">С/н · Інв. №</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Локація</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Видано</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Статус</th>
</tr>
</thead>
<tbody>
{% for equipment in equipment_page %}
<tr class="it-row" style="border-bottom:1px solid var(--color-border); cursor:pointer;" onclick="itToggleRow('equipment-{{ equipment.id }}')">
<td style="padding:0.75rem 0; text-align:center;" onclick="event.stopPropagation();">
<input type="checkbox" class="it-equip-check" value="{{ equipment.id }}" onchange="itBulkUpdate()" style="cursor:pointer;">
</td>
<td style="padding:0.75rem 0; text-align:center; color:var(--color-muted-foreground);">
<span id="it-toggle-equipment-{{ equipment.id }}" style="display:inline-block; transition:transform 150ms;">▸</span>
</td>
<td style="padding:0.75rem 1rem; color:var(--color-foreground);">
<strong>{{ equipment.equipment_type.name }}</strong>
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ equipment.brand.name|default:"" }} {{ equipment.model }}</div>
</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-size:0.8125rem;">
{{ equipment.serial_number }}{% if equipment.inventory_number %} · {{ equipment.inventory_number }}{% endif %}
</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">{{ equipment.location|default:"—" }}</td>
<td style="padding:0.75rem 1rem; color:var(--color-foreground);">{{ equipment.assigned_to.get_full_name|default:"—" }}</td>
<td style="padding:0.75rem 1rem;">
{% if equipment.status.code == 'stock' %}<span class="badge badge-muted">На складі</span>
{% elif equipment.status.code == 'assigned' %}<span class="badge badge-success">Видано</span>
{% elif equipment.status.code == 'repair' %}<span class="badge badge-warning">В ремонті</span>
{% else %}<span class="badge badge-danger">Списано</span>{% endif %}
</td>
</tr>
<tr id="it-row-equipment-{{ equipment.id }}" class="it-detail-row" style="display:none; border-bottom:1px solid var(--color-border); background:var(--color-muted);">
<td></td>
<td></td>
<td colspan="5" style="padding:1rem;">
<form hx-post="/it-manager/equipment/{{ equipment.id }}/update/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"
style="display:flex; align-items:flex-end; gap:0.75rem; flex-wrap:wrap;" onclick="event.stopPropagation();">
{% csrf_token %}
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Статус</label>
<select name="status" class="input" style="min-width:10rem;">
{% for value, label in equipment_statuses %}
<option value="{{ value }}" {% if value == equipment.status.code %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Видано кому</label>
<select name="assigned_to_id" class="input" style="min-width:14rem;">
<option value="">— (на складі)</option>
{% for emp in it_employees %}
<option value="{{ emp.id }}" {% if emp.id == equipment.assigned_to_id %}selected{% endif %}>{{ emp.last_name }} {{ emp.first_name }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">
Зберегти
<span class="btn-label-loading htmx-indicator">…</span>
</button>
{% if equipment.notes %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); flex-basis:100%;">Примітки: {{ equipment.notes }}</div>
{% endif %}
{% if equipment.warranty_until %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); flex-basis:100%;">Гарантія: {{ equipment.warranty_status }} ({{ equipment.warranty_until|date:"d.m.Y" }})</div>
{% endif %}
</form>
</td>
</tr>
{% empty %}
<tr><td colspan="7" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">Обладнання ще не додано</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "partials/pagination.html" with page=equipment_page base_url="/it-manager/" page_param="equipment_page" size_param="equipment_per_page" item_label="одиниць обладнання" %}
</div>
</div>
<!-- ══ /ВКЛАДКА: ОБЛАДНАННЯ ══ -->
<!-- ══ ВКЛАДКА: ЗАЯВКИ ══ -->
<div id="it-panel-tickets" class="it-panel" style="display:none;">
<div style="display:grid; grid-template-columns:repeat(5, minmax(0,1fr)); gap:0.75rem; margin-bottom:1.5rem;">
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Нові</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ ticket_counts.new }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">В роботі</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ ticket_counts.in_progress }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Очікування</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ ticket_counts.waiting }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Вирішені</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ ticket_counts.resolved|add:ticket_counts.closed }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Прострочені</div>
<div style="font-size:1.5rem; font-weight:500; color:{% if ticket_overdue_count %}var(--color-destructive){% else %}var(--color-foreground){% endif %};">{{ ticket_overdue_count }}</div>
</div>
</div>
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
<thead>
<tr style="border-bottom:1px solid var(--color-border);">
<th style="width:2rem;"></th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">№ / Тема</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Пріоритет</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Заявник</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Виконавець</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Дата</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Статус</th>
</tr>
</thead>
<tbody>
{% for ticket in tickets_page %}
<tr class="it-row" style="border-bottom:1px solid var(--color-border); cursor:pointer;" onclick="itToggleRow('ticket-{{ ticket.id }}')">
<td style="padding:0.75rem 0; text-align:center; color:var(--color-muted-foreground);">
<span id="it-toggle-ticket-{{ ticket.id }}" style="display:inline-block; transition:transform 150ms;">▸</span>
</td>
<td style="padding:0.75rem 1rem; color:var(--color-foreground);">
<strong>{{ ticket.number }}</strong>
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ ticket.title }}{% if ticket.is_overdue %} <span class="badge badge-danger">прострочено</span>{% endif %}</div>
</td>
<td style="padding:0.75rem 1rem;">
{% if ticket.priority.code == 'critical' %}<span class="badge badge-danger">Критичний</span>
{% elif ticket.priority.code == 'high' %}<span class="badge badge-warning">Високий</span>
{% elif ticket.priority.code == 'medium' %}<span class="badge badge-info">Середній</span>
{% else %}<span class="badge badge-muted">Низький</span>{% endif %}
</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">{{ ticket.requester.get_full_name|default:ticket.requester.username }}</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">{{ ticket.assignee.get_full_name|default:"—" }}</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-size:0.8125rem;">{{ ticket.created_at|date:"d.m.Y" }}</td>
<td style="padding:0.75rem 1rem;">
{% if ticket.status.code == 'new' %}<span class="badge badge-info">Нова</span>
{% elif ticket.status.code == 'in_progress' %}<span class="badge badge-warning">В роботі</span>
{% elif ticket.status.code == 'waiting' %}<span class="badge badge-muted">Очікування</span>
{% elif ticket.status.code == 'resolved' %}<span class="badge badge-success">Вирішена</span>
{% else %}<span class="badge badge-muted">Закрита</span>{% endif %}
</td>
</tr>
<tr id="it-row-ticket-{{ ticket.id }}" class="it-detail-row" style="display:none; border-bottom:1px solid var(--color-border); background:var(--color-muted);">
<td></td>
<td colspan="6" style="padding:1rem;">
<div style="font-size:0.8125rem; color:var(--color-foreground); margin-bottom:0.75rem; white-space:pre-wrap;">{{ ticket.description }}</div>
{% if ticket.comments.all %}
<div style="display:flex; flex-direction:column; gap:0.5rem; margin-bottom:0.75rem;">
{% for comment in ticket.comments.all %}
<div style="background:var(--color-card); border:1px solid var(--color-border); border-radius:0.5rem; padding:0.5rem 0.75rem;">
<div style="font-size:0.75rem; color:var(--color-muted-foreground); display:flex; justify-content:space-between;">
<span>{{ comment.author.get_full_name|default:comment.author.username }} · {{ comment.created_at|date:"d.m.Y H:i" }}</span>
{% if comment.is_internal %}<span class="badge badge-muted">внутрішній</span>{% endif %}
</div>
<div style="font-size:0.8125rem; color:var(--color-foreground); margin-top:0.25rem; white-space:pre-wrap;">{{ comment.text }}</div>
</div>
{% endfor %}
</div>
{% endif %}
<form hx-post="/it-manager/tickets/{{ ticket.id }}/update/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"
style="display:flex; align-items:flex-end; gap:0.75rem; flex-wrap:wrap; margin-bottom:0.75rem;" onclick="event.stopPropagation();">
{% csrf_token %}
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Статус</label>
<select name="status" class="input" style="min-width:10rem;">
{% for value, label in ticket_statuses %}
<option value="{{ value }}" {% if value == ticket.status.code %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Виконавець</label>
<select name="assignee_id" class="input" style="min-width:12rem;">
<option value="">— не призначено</option>
{% for emp in it_staff %}
<option value="{{ emp.id }}" {% if emp.id == ticket.assignee_id %}selected{% endif %}>{{ emp.last_name }} {{ emp.first_name }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">
Зберегти
<span class="btn-label-loading htmx-indicator">…</span>
</button>
</form>
<form hx-post="/it-manager/tickets/{{ ticket.id }}/comment/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"
style="display:flex; gap:0.5rem; align-items:flex-start;" onclick="event.stopPropagation();">
{% csrf_token %}
<input type="text" name="text" placeholder="Коментар..." class="input" style="flex:1;">
<label style="display:flex; align-items:center; gap:0.25rem; font-size:0.75rem; color:var(--color-muted-foreground); white-space:nowrap; padding-top:0.5rem;">
<input type="checkbox" name="is_internal"> внутрішній
</label>
<button type="submit" class="btn btn-secondary" style="border:1px solid var(--color-border);">
Додати
<span class="btn-label-loading htmx-indicator">…</span>
</button>
</form>
</td>
</tr>
{% empty %}
<tr><td colspan="7" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">Заявок поки немає</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "partials/pagination.html" with page=tickets_page base_url="/it-manager/" page_param="tickets_page" size_param="tickets_per_page" item_label="заявок" %}
</div>
</div>
<!-- ══ /ВКЛАДКА: ЗАЯВКИ ══ -->
<!-- ══ ВКЛАДКА: ВИКОНАНІ РОБОТИ ══ -->
<div id="it-panel-worklog" class="it-panel" style="display:none;">
<div style="display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:0.75rem; margin-bottom:1.5rem;">
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Записів цього місяця</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ month_count }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Годин цього місяця</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ month_hours }}</div>
</div>
</div>
<div style="display:flex; justify-content:flex-end; margin-bottom:1rem;">
<button type="button" class="btn btn-primary" onclick="itPanelOpen('it-worklog-panel')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
</svg>
Додати запис
</button>
</div>
<!-- Виїзна панель: новий запис про виконану роботу -->
<div id="it-worklog-panel-overlay" onclick="itPanelClose('it-worklog-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div>
<div id="it-worklog-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;">
<form hx-post="/it-manager/worklog/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">Додати запис про виконану роботу</span>
<button type="button" onclick="itPanelClose('it-worklog-panel')" class="btn btn-ghost btn-icon" aria-label="Закрити">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Дата</label>
<input type="date" name="date" value="{% now 'Y-m-d' %}" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Вид робіт <span style="color:var(--color-destructive);">*</span></label>
<select name="work_type" required class="input" style="width:100%;" onchange="dqaHandleChange(this, 'worklog_type', 'code')">
{% for value, label in worklog_types %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
<option value="__new__">+ Додати новий вид робіт...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Локація</label>
<div class="searchable-select" data-placeholder="Пошук за адресою чи номером аптеки...">
<select name="location_id" hidden>
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}">{{ location }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Витрачено годин</label>
<input type="number" step="0.5" min="0" name="hours_spent" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Обладнання</label>
<select name="equipment_id" class="input" style="width:100%;">
<option value="">—</option>
{% for equipment in equipment_list %}
<option value="{{ equipment.id }}">{{ equipment.equipment_model }} [{{ equipment.serial_number }}]</option>
{% endfor %}
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Заявка</label>
<select name="ticket_id" class="input" style="width:100%;">
<option value="">—</option>
{% for ticket in tickets %}
<option value="{{ ticket.id }}">{{ ticket.number }} — {{ ticket.title }}</option>
{% endfor %}
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Опис робіт <span style="color:var(--color-destructive);">*</span></label>
<textarea name="description" required style="width:100%; min-height:4rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Результат</label>
<textarea name="result" style="width:100%; min-height:3.5rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
<div>
<button type="submit" class="btn btn-primary" style="width:100%; justify-content:center;">
Додати запис
<span class="btn-label-loading htmx-indicator">Збереження…</span>
</button>
</div>
</div>
</form>
</div>
<!-- Журнал -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
<thead>
<tr style="border-bottom:1px solid var(--color-border);">
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Дата</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Виконавець</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Вид робіт</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Опис</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Локація</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Годин</th>
</tr>
</thead>
<tbody>
{% for log in worklogs_page %}
<tr style="border-bottom:1px solid var(--color-border);">
<td style="padding:0.625rem 1rem; color:var(--color-muted-foreground); white-space:nowrap;">{{ log.date|date:"d.m.Y" }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-foreground);">{{ log.technician.get_full_name|default:log.technician.username }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-muted-foreground);">{{ log.work_type.name }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-foreground); max-width:22rem;">{{ log.description|truncatechars:120 }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-muted-foreground); font-size:0.8125rem;">{{ log.location|default:"—" }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-foreground);">{{ log.hours_spent|default:"—" }}</td>
</tr>
{% empty %}
<tr><td colspan="6" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">Записів ще немає</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "partials/pagination.html" with page=worklogs_page base_url="/it-manager/" page_param="worklogs_page" size_param="worklogs_per_page" item_label="записів" %}
</div>
</div>
<!-- ══ /ВКЛАДКА: ВИКОНАНІ РОБОТИ ══ -->
<!-- ══ ВКЛАДКА: ВИТРАТНІ МАТЕРІАЛИ ══ -->
<div id="it-panel-consumables" class="it-panel" style="display:none;">
<div style="display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:0.75rem; margin-bottom:1.5rem;">
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Всього позицій</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ consumables_count }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Закінчується / на заміну</div>
<div style="font-size:1.5rem; font-weight:500; color:{% if consumable_low_count %}var(--color-destructive){% else %}var(--color-foreground){% endif %};">{{ consumable_low_count }}</div>
</div>
</div>
<div style="display:flex; justify-content:flex-end; margin-bottom:1rem;">
<button type="button" class="btn btn-primary" onclick="itPanelOpen('it-consumable-panel')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
</svg>
Додати матеріал
</button>
</div>
<!-- Виїзна панель: новий витратний матеріал -->
<div id="it-consumable-panel-overlay" onclick="itPanelClose('it-consumable-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div>
<div id="it-consumable-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;">
<form hx-post="/it-manager/consumables/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">Додати витратний матеріал</span>
<button type="button" onclick="itPanelClose('it-consumable-panel')" class="btn btn-ghost btn-icon" aria-label="Закрити">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Тип <span style="color:var(--color-destructive);">*</span></label>
<select name="consumable_type" required class="input" style="width:100%;" onchange="dqaHandleChange(this, 'consumable_type', 'code')">
{% for value, label in consumable_types %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
<option value="__new__">+ Додати новий тип...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Колір</label>
<select name="color" class="input" style="width:100%;" onchange="dqaHandleChange(this, 'consumable_color', 'code')">
{% for value, label in consumable_colors %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
<option value="__new__">+ Додати новий колір...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Виробник</label>
<input type="text" name="brand" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Модель / артикул <span style="color:var(--color-destructive);">*</span></label>
<input type="text" name="model_number" required class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Принтер</label>
<select name="equipment_id" class="input" style="width:100%;">
<option value="">—</option>
{% for printer in printers %}
<option value="{{ printer.id }}">{{ printer.equipment_model }} [{{ printer.serial_number }}]</option>
{% endfor %}
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Локація зберігання</label>
<div class="searchable-select" data-placeholder="Пошук за адресою чи номером аптеки...">
<select name="location_id" hidden>
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}">{{ location }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Ресурс (сторінок)</label>
<input type="number" min="0" name="page_yield" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Дата покупки</label>
<input type="date" name="purchase_date" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Примітки</label>
<textarea name="notes" style="width:100%; min-height:3rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
<div>
<button type="submit" class="btn btn-primary" style="width:100%; justify-content:center;">
Додати
<span class="btn-label-loading htmx-indicator">Збереження…</span>
</button>
</div>
</div>
</form>
</div>
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
<thead>
<tr style="border-bottom:1px solid var(--color-border);">
<th style="width:2rem;"></th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Тип / Модель</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Колір</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Принтер</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Статус</th>
</tr>
</thead>
<tbody>
{% for consumable in consumables_page %}
<tr class="it-row" style="border-bottom:1px solid var(--color-border); cursor:pointer;" onclick="itToggleRow('consumable-{{ consumable.id }}')">
<td style="padding:0.75rem 0; text-align:center; color:var(--color-muted-foreground);">
<span id="it-toggle-consumable-{{ consumable.id }}" style="display:inline-block; transition:transform 150ms;">▸</span>
</td>
<td style="padding:0.75rem 1rem; color:var(--color-foreground);">
<strong>{{ consumable.consumable_type.name }}</strong>
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ consumable.brand }} {{ consumable.model_number }}</div>
</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">{{ consumable.color.name }}</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">{{ consumable.equipment|default:"—" }}</td>
<td style="padding:0.75rem 1rem;">
{% if consumable.is_low %}<span class="badge badge-danger">{{ consumable.status.name }}</span>
{% elif consumable.status.code == 'installed' %}<span class="badge badge-success">{{ consumable.status.name }}</span>
{% else %}<span class="badge badge-muted">{{ consumable.status.name }}</span>{% endif %}
</td>
</tr>
<tr id="it-row-consumable-{{ consumable.id }}" class="it-detail-row" style="display:none; border-bottom:1px solid var(--color-border); background:var(--color-muted);">
<td></td>
<td colspan="4" style="padding:1rem;">
<form hx-post="/it-manager/consumables/{{ consumable.id }}/update/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"
style="display:flex; align-items:flex-end; gap:0.75rem; flex-wrap:wrap;" onclick="event.stopPropagation();">
{% csrf_token %}
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Статус</label>
<select name="status" class="input" style="min-width:12rem;">
{% for value, label in consumable_statuses %}
<option value="{{ value }}" {% if value == consumable.status.code %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">
Зберегти
<span class="btn-label-loading htmx-indicator">…</span>
</button>
{% if consumable.page_yield %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">Ресурс: {{ consumable.page_yield }} стор.</div>
{% endif %}
{% if consumable.notes %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); flex-basis:100%;">Примітки: {{ consumable.notes }}</div>
{% endif %}
</form>
</td>
</tr>
{% empty %}
<tr><td colspan="5" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">Витратних матеріалів ще не додано</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "partials/pagination.html" with page=consumables_page base_url="/it-manager/" page_param="consumables_page" size_param="consumables_per_page" item_label="матеріалів" %}
</div>
</div>
<!-- ══ /ВКЛАДКА: ВИТРАТНІ МАТЕРІАЛИ ══ -->
<!-- ══ ВКЛАДКА: ПРОВАЙДЕРИ ══ -->
<div id="it-panel-providers" class="it-panel" style="display:none;">
<div style="display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:0.75rem; margin-bottom:1.5rem;">
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Провайдерів</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ providers|length }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Договорів</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ contracts_count }}</div>
</div>
<div class="stat-card" style="padding:1rem 1.25rem;">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">Закінчуються за 30 днів</div>
<div style="font-size:1.5rem; font-weight:500; color:{% if contracts_expiring_count %}var(--color-destructive){% else %}var(--color-foreground){% endif %};">{{ contracts_expiring_count }}</div>
</div>
</div>
<div style="display:flex; justify-content:flex-end; gap:0.5rem; margin-bottom:1rem;">
<button type="button" class="btn btn-secondary" onclick="itPanelOpen('it-provider-panel')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
</svg>
Додати провайдера
</button>
<button type="button" class="btn btn-primary" onclick="itPanelOpen('it-contract-panel')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
</svg>
Додати договір
</button>
</div>
<!-- Список провайдерів -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden; margin-bottom:1.25rem;">
<div style="padding:0.875rem 1.25rem; border-bottom:1px solid var(--color-border);">
<span style="font-size:0.8125rem; font-weight:500; color:var(--color-foreground);">Провайдери</span>
</div>
<div style="display:flex; flex-wrap:wrap; gap:0.625rem; padding:1rem 1.25rem;">
{% for provider in providers %}
<div style="display:flex; align-items:center; gap:0.5rem; background:var(--color-muted); border-radius:0.5rem; padding:0.5rem 0.75rem;">
<div>
<div style="font-size:0.8125rem; font-weight:500; color:var(--color-foreground);">{{ provider.name }}</div>
<div style="font-size:0.75rem; color:var(--color-muted-foreground);">{{ provider.phone|default:"—" }}{% if provider.website %} · {{ provider.website }}{% endif %}</div>
</div>
<span class="badge badge-info">{{ provider.active_contracts_count }}</span>
</div>
{% empty %}
<div style="color:var(--color-muted-foreground); font-size:0.8125rem;">Провайдерів ще немає</div>
{% endfor %}
</div>
</div>
<!-- Виїзна панель: новий провайдер -->
<div id="it-provider-panel-overlay" onclick="itPanelClose('it-provider-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div>
<div id="it-provider-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;">
<form hx-post="/it-manager/providers/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">Новий провайдер</span>
<button type="button" onclick="itPanelClose('it-provider-panel')" class="btn btn-ghost btn-icon" aria-label="Закрити">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Назва <span style="color:var(--color-destructive);">*</span></label>
<input type="text" name="name" required class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Телефон</label>
<input type="text" name="phone" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Email</label>
<input type="email" name="email" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Сайт</label>
<input type="url" name="website" placeholder="https://" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Телефон техпідтримки</label>
<input type="text" name="support_phone" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Email техпідтримки</label>
<input type="email" name="support_email" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Примітки</label>
<textarea name="notes" style="width:100%; min-height:3rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
<div>
<button type="submit" class="btn btn-primary" style="width:100%; justify-content:center;">
Додати провайдера
<span class="btn-label-loading htmx-indicator">…</span>
</button>
</div>
</div>
</form>
</div>
<!-- Виїзна панель: новий договір -->
<div id="it-contract-panel-overlay" onclick="itPanelClose('it-contract-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div>
<div id="it-contract-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;">
<form hx-post="/it-manager/contracts/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">Новий договір</span>
<button type="button" onclick="itPanelClose('it-contract-panel')" class="btn btn-ghost btn-icon" aria-label="Закрити">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Провайдер <span style="color:var(--color-destructive);">*</span></label>
<select name="provider_id" required class="input" style="width:100%;">
<option value="">—</option>
{% for provider in providers %}
<option value="{{ provider.id }}">{{ provider.name }}</option>
{% endfor %}
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Локація <span style="color:var(--color-destructive);">*</span></label>
<div class="searchable-select" data-placeholder="Пошук за адресою чи номером аптеки...">
<select name="location_id" required hidden>
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}">{{ location }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Номер договору <span style="color:var(--color-destructive);">*</span></label>
<input type="text" name="contract_number" required class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Тип послуги <span style="color:var(--color-destructive);">*</span></label>
<select name="service_type" required class="input" style="width:100%;" onchange="dqaHandleChange(this, 'contract_service_type', 'code'); itContractServiceToggle(this.value)">
{% for value, label in contract_service_types %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
<option value="__new__">+ Додати новий тип...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Технологія підключення</label>
<select name="connection_type" class="input" style="width:100%;" onchange="dqaHandleChange(this, 'contract_connection_type', 'code')">
<option value="">—</option>
{% for value, label in contract_connection_types %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
<option value="__new__">+ Додати нову технологію...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Дата початку <span style="color:var(--color-destructive);">*</span></label>
<input type="date" name="start_date" required class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Дата закінчення</label>
<input type="date" name="end_date" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Вартість/міс.</label>
<input type="number" step="0.01" min="0" name="monthly_cost" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Швидкість ↓ Мбіт/с</label>
<input type="number" min="0" name="bandwidth_down" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Швидкість ↑ Мбіт/с</label>
<input type="number" min="0" name="bandwidth_up" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Особовий рахунок</label>
<input type="text" name="account_number" class="input" style="width:100%;">
</div>
<div id="it-contract-ip-block" style="display:none; background:var(--color-muted); border-radius:0.625rem; padding:0.875rem 1rem;">
<label style="display:flex; align-items:center; gap:0.5rem; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); cursor:pointer;">
<input type="checkbox" name="dedicated_ip" onchange="document.getElementById('it-contract-ip-field').style.display = this.checked ? '' : 'none'">
Виділений IP
</label>
<div id="it-contract-ip-field" style="display:none; margin-top:0.625rem;">
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">IP-адреси</label>
<textarea name="static_ips" placeholder="По одній IP-адресі на рядок" style="width:100%; min-height:3rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Примітки</label>
<textarea name="notes" style="width:100%; min-height:3rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
<div>
<button type="submit" class="btn btn-primary" style="width:100%; justify-content:center;">
Додати договір
<span class="btn-label-loading htmx-indicator">…</span>
</button>
</div>
</div>
</form>
</div>
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
<thead>
<tr style="border-bottom:1px solid var(--color-border);">
<th style="width:2rem;"></th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Провайдер / Локація</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Тип послуги</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Швидкість</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Закінчення</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Статус</th>
</tr>
</thead>
<tbody>
{% for contract in contracts_page %}
<tr class="it-row" style="border-bottom:1px solid var(--color-border); cursor:pointer;" onclick="itToggleRow('contract-{{ contract.id }}')">
<td style="padding:0.75rem 0; text-align:center; color:var(--color-muted-foreground);">
<span id="it-toggle-contract-{{ contract.id }}" style="display:inline-block; transition:transform 150ms;">▸</span>
</td>
<td style="padding:0.75rem 1rem; color:var(--color-foreground);">
<strong>{{ contract.provider.name }}</strong> <span style="font-size:0.75rem; color:var(--color-muted-foreground);">№{{ contract.contract_number }}</span>
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ contract.location }}</div>
</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">{{ contract.service_type.name }}</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-size:0.8125rem;">{{ contract.bandwidth_display }}</td>
<td style="padding:0.75rem 1rem; color:{% if contract.is_expiring_soon %}var(--color-destructive){% else %}var(--color-muted-foreground){% endif %};">{{ contract.end_date|date:"d.m.Y"|default:"—" }}</td>
<td style="padding:0.75rem 1rem;">
{% if contract.status.code == 'active' %}<span class="badge badge-success">{{ contract.status.name }}</span>
{% elif contract.status.code == 'suspended' %}<span class="badge badge-warning">{{ contract.status.name }}</span>
{% else %}<span class="badge badge-danger">{{ contract.status.name }}</span>{% endif %}
</td>
</tr>
<tr id="it-row-contract-{{ contract.id }}" class="it-detail-row" style="display:none; border-bottom:1px solid var(--color-border); background:var(--color-muted);">
<td></td>
<td colspan="5" style="padding:1rem;">
<form hx-post="/it-manager/contracts/{{ contract.id }}/update/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]"
style="display:flex; align-items:flex-end; gap:0.75rem; flex-wrap:wrap;" onclick="event.stopPropagation();">
{% csrf_token %}
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">Статус</label>
<select name="status" class="input" style="min-width:12rem;">
{% for value, label in contract_statuses %}
<option value="{{ value }}" {% if value == contract.status.code %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">
Зберегти
<span class="btn-label-loading htmx-indicator">…</span>
</button>
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">Рахунок: {{ contract.account_number|default:"—" }} · {{ contract.monthly_cost|default:"—" }} грн/міс</div>
</form>
</td>
</tr>
{% empty %}
<tr><td colspan="6" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">Договорів ще немає</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "partials/pagination.html" with page=contracts_page base_url="/it-manager/" page_param="contracts_page" size_param="contracts_per_page" item_label="договорів" %}
</div>
</div>
<!-- ══ /ВКЛАДКА: ПРОВАЙДЕРИ ══ -->
<!-- ══ ВКЛАДКА: ОБРАЩЕННЯ ══ -->
<div id="it-panel-servicecalls" class="it-panel" style="display:none;">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:1rem;">
<span style="font-size:0.875rem; color:var(--color-muted-foreground);">{{ service_calls_count }} звернень</span>
<button type="button" class="btn btn-primary" onclick="itPanelOpen('it-servicecall-panel')">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" x2="12" y1="5" y2="19"/><line x1="5" x2="19" y1="12" y2="12"/>
</svg>
Нове звернення
</button>
</div>
<!-- Виїзна панель: нове звернення -->
<div id="it-servicecall-panel-overlay" onclick="itPanelClose('it-servicecall-panel')" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.4); z-index:1000;"></div>
<div id="it-servicecall-panel" style="position:fixed; top:0; right:0; height:100vh; width:26rem; max-width:92vw; background:var(--color-card); box-shadow:-8px 0 24px rgba(0,0,0,0.18); z-index:1001; transform:translateX(100%); transition:transform 250ms ease; overflow-y:auto;">
<form hx-post="/it-manager/servicecalls/create/" hx-target="#main-content" hx-indicator="#loader, find .btn-label-loading" hx-disabled-elt="find button[type=submit]">
{% csrf_token %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; position:sticky; top:0; background:var(--color-card); z-index:1;">
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">Нове звернення</span>
<button type="button" onclick="itPanelClose('it-servicecall-panel')" class="btn btn-ghost btn-icon" aria-label="Закрити">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6 6 18M6 6l12 12"/></svg>
</button>
</div>
<div style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Хто звернувся <span style="color:var(--color-destructive);">*</span></label>
<select name="caller_id" required class="input" style="width:100%;">
<option value="">—</option>
{% for emp in it_employees %}
<option value="{{ emp.id }}">{{ emp.last_name }} {{ emp.first_name }}</option>
{% endfor %}
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Канал <span style="color:var(--color-destructive);">*</span></label>
<select name="channel" required class="input" style="width:100%;" onchange="dqaHandleChange(this, 'servicecall_channel', 'code')">
{% for value, label in servicecall_channels %}
<option value="{{ value }}">{{ label }}</option>
{% endfor %}
<option value="__new__">+ Додати новий канал...</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Витрачено хвилин</label>
<input type="number" min="0" name="minutes_spent" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Опис звернення <span style="color:var(--color-destructive);">*</span></label>
<textarea name="description" required style="width:100%; min-height:3.5rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">Рішення</label>
<textarea name="resolution" style="width:100%; min-height:3rem; resize:vertical; background:var(--color-card); border:1px solid var(--color-input); border-radius:var(--radius); padding:0.4375rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
</div>
<div>
<button type="submit" class="btn btn-primary" style="width:100%; justify-content:center;">
Додати звернення
<span class="btn-label-loading htmx-indicator">Збереження…</span>
</button>
</div>
</div>
</form>
</div>
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
<thead>
<tr style="border-bottom:1px solid var(--color-border);">
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Дата</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Хто звернувся</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Канал</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Прийняв</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Опис</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">Тривалість</th>
</tr>
</thead>
<tbody>
{% for call in service_calls_page %}
<tr style="border-bottom:1px solid var(--color-border);">
<td style="padding:0.625rem 1rem; color:var(--color-muted-foreground); white-space:nowrap;">{{ call.date_time|date:"d.m.Y H:i" }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-foreground);">{{ call.caller.get_full_name|default:call.caller.username }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-muted-foreground);">{{ call.channel.name }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-muted-foreground);">{{ call.handler.get_full_name|default:"—" }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-foreground); max-width:20rem;">{{ call.description|truncatechars:100 }}</td>
<td style="padding:0.625rem 1rem; color:var(--color-muted-foreground);">{{ call.duration_display }}</td>
</tr>
{% empty %}
<tr><td colspan="6" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">Звернень ще немає</td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "partials/pagination.html" with page=service_calls_page base_url="/it-manager/" page_param="servicecalls_page" size_param="servicecalls_per_page" item_label="звернень" %}
</div>
</div>
<!-- ══ /ВКЛАДКА: ОБРАЩЕННЯ ══ -->
{% if it_active_tab and it_active_tab != 'equipment' %}
<script>itTabSwitch('{{ it_active_tab }}');</script>
{% endif %}
<script>initSearchableSelects(document);</script>
</div>