Files
ACORE/templates/pages/it-manager.html
T

1562 lines
142 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 %}
{% load i18n %}
{% with active_tab=it_active_tab|default:"equipment" %}
<div class="page-content" data-it-active-tab="{{ active_tab }}">
<div style="margin-bottom:1.5rem;">
<h1 style="font-size:1.25rem; font-weight:500; color:var(--color-foreground);">{% trans "IT-отдел" %}</h1>
<p style="font-size:0.875rem; color:var(--color-muted-foreground); margin-top:0.25rem;">{% trans "Инвентаризация оборудования, очередь заявок и журнал выполненных работ" %}</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{% if active_tab == 'equipment' %} it-tab-active{% endif %}" 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; {% if active_tab == 'equipment' %}background:var(--color-card); color:var(--color-card-foreground); box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Оборудование" %}</button>
<button type="button" class="it-tab-btn{% if active_tab == 'tickets' %} it-tab-active{% endif %}" 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; {% if active_tab == 'tickets' %}background:var(--color-card); color:var(--color-card-foreground); box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Заявки" %}</button>
<button type="button" class="it-tab-btn{% if active_tab == 'worklog' %} it-tab-active{% endif %}" 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; {% if active_tab == 'worklog' %}background:var(--color-card); color:var(--color-card-foreground); box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Выполненные работы" %}</button>
<button type="button" class="it-tab-btn{% if active_tab == 'consumables' %} it-tab-active{% endif %}" 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; {% if active_tab == 'consumables' %}background:var(--color-card); color:var(--color-card-foreground); box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Расходные материалы" %}</button>
<button type="button" class="it-tab-btn{% if active_tab == 'providers' %} it-tab-active{% endif %}" 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; {% if active_tab == 'providers' %}background:var(--color-card); color:var(--color-card-foreground); box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Провайдеры" %}</button>
<button type="button" class="it-tab-btn{% if active_tab == 'servicecalls' %} it-tab-active{% endif %}" 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; {% if active_tab == 'servicecalls' %}background:var(--color-card); color:var(--color-card-foreground); box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}background:transparent; color:var(--color-muted-foreground);{% endif %}">{% trans "Обращение" %}</button>
{% if it_can_view_monthly_report %}
<a href="/reports/it/monthly/"
hx-get="/reports/it/monthly/" hx-target="#main-content" hx-push-url="/reports/it/monthly/" hx-indicator="#loader"
class="it-tab-btn"
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); text-decoration:none; display:inline-flex; align-items:center;">
{% trans "Месячный отчёт" %} →
</a>
{% endif %}
</div>
<!-- ══ ВКЛАДКА: ОБЛАДНАННЯ ══ -->
<div id="it-panel-equipment" class="it-panel"{% if active_tab != 'equipment' %} style="display:none;"{% endif %}>
<div style="display:grid; grid-template-columns:repeat(4, minmax(0,1fr)); gap:0.75rem; margin-bottom:1.5rem;">
<a href="/it-manager/?tab=equipment"
hx-get="/it-manager/?tab=equipment" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
class="stat-card" style="padding:1rem 1.25rem; text-decoration:none; cursor:pointer; display:block;{% if not equipment_filters.status %} outline:2px solid var(--color-primary); outline-offset:-2px;{% endif %}">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">{% trans "Всего единиц" %}</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_total_count }}</div>
</a>
<a href="/it-manager/?tab=equipment&status=stock"
hx-get="/it-manager/?tab=equipment&status=stock" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
class="stat-card" style="padding:1rem 1.25rem; text-decoration:none; cursor:pointer; display:block;{% if equipment_filters.status == 'stock' %} outline:2px solid var(--color-primary); outline-offset:-2px;{% endif %}">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">{% trans "На складе" %}</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_counts.stock }}</div>
</a>
<a href="/it-manager/?tab=equipment&status=assigned"
hx-get="/it-manager/?tab=equipment&status=assigned" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
class="stat-card" style="padding:1rem 1.25rem; text-decoration:none; cursor:pointer; display:block;{% if equipment_filters.status == 'assigned' %} outline:2px solid var(--color-primary); outline-offset:-2px;{% endif %}">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">{% trans "Выдано" %}</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_counts.assigned }}</div>
</a>
<a href="/it-manager/?tab=equipment&status=repair"
hx-get="/it-manager/?tab=equipment&status=repair" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
class="stat-card" style="padding:1rem 1.25rem; text-decoration:none; cursor:pointer; display:block;{% if equipment_filters.status == 'repair' %} outline:2px solid var(--color-primary); outline-offset:-2px;{% endif %}">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">{% trans "В ремонте / списано" %}</div>
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ equipment_counts.repair|add:equipment_counts.written_off }}</div>
</a>
</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>
{% trans "Каталог моделей" %} ({{ 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>
{% trans "Добавить экземпляры" %}
</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);">{% trans "Добавить экземпляры" %}</span>
<button type="button" onclick="itPanelClose('it-equipment-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
<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;">{% trans "Модель из каталога" %} <span style="color:var(--color-destructive);">*</span></label>
<div class="searchable-select" data-placeholder="{% trans 'Поиск модели по названию или бренду...' %}">
<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;">{% trans "Нет нужной?" %} <a href="#" onclick="itPanelClose('it-equipment-panel'); itPanelOpen('it-equipment-models-panel'); return false;" style="color:var(--color-primary);">{% trans "Добавить модель в каталог" %}</a></div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Серийные номера" %} <span style="color:var(--color-destructive);">*</span></label>
<textarea name="serial_numbers" required placeholder="{% trans 'По одному в строку — вставьте список серийников, например' %}&#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;">{% trans "Сколько серийников — столько единиц будет создано. Дубликаты и уже имеющиеся пропускаются." %}</div>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Инвентарные номера" %} <span style="font-weight:400; color:var(--color-muted-foreground);">{% trans "(необязательно, по одному на строку)" %}</span></label>
<textarea name="inventory_numbers" placeholder="{% trans 'По одному на строку — столько же строк, сколько серийников' %}"
style="width:100%; min-height: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-mono, monospace); outline:none; box-sizing:border-box;"></textarea>
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.375rem;">{% trans "Если заполняете — число строк должно совпадать с серийными номерами. Пустая строка = без инв. номера." %}</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;">{% trans "Дата покупки" %}</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;">{% trans "Гарантия до" %}</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;">{% trans "Сразу выдать" %} <span style="font-weight:400; color:var(--color-muted-foreground);">{% trans "(необязательно)" %}</span></label>
{% include "partials/it-equipment-assign-fields.html" with widget_id="bulk-create" selected_target="" selected_location_id=None selected_employee_id=None require_target=False allow_empty=True %}
</div>
<div style="display:flex; gap:0.5rem;">
<button type="submit" class="btn btn-primary" style="flex:1;">
{% trans "Создать экземпляры" %}
<span class="btn-label-loading htmx-indicator">{% trans "Сохранение…" %}</span>
</button>
<button type="button" class="btn btn-secondary" style="border:1px solid var(--color-border);" onclick="itPanelClose('it-equipment-panel')">{% trans "Отменить" %}</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);">{% trans "Каталог моделей" %}</span>
<button type="button" onclick="itPanelClose('it-equipment-models-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
<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);">{% trans "Новая модель" %}</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Тип" %} <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__">{% trans "+ Добавить новый тип..." %}</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Бренд" %}</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__">{% trans "+ Добавить новый бренд..." %}</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Модель" %} <span style="color:var(--color-destructive);">*</span></label>
<input type="text" name="name" required placeholder="{% trans 'Например: 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;">{% trans "Гарантия (мес.)" %} <span style="font-weight:400; color:var(--color-muted-foreground);">{% trans "(необязательно)" %}</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%;">
{% trans "Добавить модель" %}
<span class="btn-label-loading htmx-indicator">{% trans "Сохранение…" %}</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;">{% trans "В каталоге" %} ({{ 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 }} {% trans "ед." %}</span>
</div>
{% empty %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "Каталог пуст — добавьте первую модель." %}</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;">{% trans "Выдать" %} <span id="it-bulk-assign-count">0</span> {% trans "ед.:" %}</div>
{% include "partials/it-equipment-assign-fields.html" with widget_id="bulk-assign" selected_target="" selected_location_id=None selected_employee_id=None require_target=True allow_empty=False %}
<button type="submit" class="btn btn-primary">{% trans "Выдать" %}</button>
<button type="button" class="btn btn-secondary" style="border:1px solid var(--color-border);"
onclick="itEquipmentOpenLabels()">{% trans "Этикетки QR / EAN-13" %}</button>
<button type="button" class="btn btn-ghost" onclick="itBulkClearSelection()">{% trans "Отменить выбор" %}</button>
</form>
</div>
<form id="it-equipment-filters"
hx-get="/it-manager/"
hx-target="#main-content"
hx-push-url="true"
hx-indicator="#loader"
hx-trigger="submit, change from:find select, keyup changed delay:400ms from:find input[name='q']"
style="display:flex; align-items:flex-end; gap:0.75rem; flex-wrap:wrap; margin-bottom:1rem;">
<input type="hidden" name="tab" value="equipment">
<div style="flex:1; min-width:12rem;">
<label for="it-equipment-q" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Поиск" %}</label>
<input type="search" id="it-equipment-q" name="q" value="{{ equipment_filters.q }}"
placeholder="{% trans 'Серийный, инв. №, модель, бренд…' %}"
class="input" style="width:100%;">
</div>
<div>
<label for="it-equipment-status" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Статус" %}</label>
<select id="it-equipment-status" name="status" class="input" style="min-width:9rem; width:auto;">
<option value="">{% trans "Все" %}</option>
{% for value, label in equipment_statuses %}
<option value="{{ value }}" {% if equipment_filters.status == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="it-equipment-type" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Тип" %}</label>
<select id="it-equipment-type" name="equipment_type" class="input" style="min-width:9rem; width:auto;">
<option value="">{% trans "Все" %}</option>
{% for value, label in equipment_types %}
<option value="{{ value }}" {% if equipment_filters.equipment_type == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="it-equipment-brand" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Бренд" %}</label>
<select id="it-equipment-brand" name="brand" class="input" style="min-width:9rem; width:auto;">
<option value="">{% trans "Все" %}</option>
{% for brand in equipment_brands %}
<option value="{{ brand.id }}" {% if equipment_filters.brand == brand.id|stringformat:"s" %}selected{% endif %}>{{ brand.name }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="it-equipment-location" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Локация" %}</label>
<select id="it-equipment-location" name="location_id" class="input" style="min-width:12rem; width:auto;">
<option value="">{% trans "Все" %}</option>
{% for location in it_locations %}
<option value="{{ location.id }}" {% if equipment_filters.location_id == location.id %}selected{% endif %}>{{ location }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="it-equipment-assignee" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Сотрудник" %}</label>
<select id="it-equipment-assignee" name="assigned_to" class="input" style="min-width:12rem; width:auto;">
<option value="">{% trans "Все" %}</option>
{% for emp in it_employees %}
<option value="{{ emp.id }}" {% if equipment_filters.assigned_to == emp.id %}selected{% endif %}>{{ emp.get_full_name|default:emp.username }}</option>
{% endfor %}
</select>
</div>
{% if equipment_filters_active %}
<a href="/it-manager/?tab=equipment"
hx-get="/it-manager/?tab=equipment" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
class="btn btn-ghost" style="margin-bottom:0.05rem;">{% trans "Сбросить" %}</a>
{% endif %}
</form>
<!-- Список обладнання -->
<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="{% trans 'Выделить все на странице' %}" 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;">{% trans "Тип / Бренд / Модель" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "С/н · Инв. №" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Аптека / локация" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Сотрудник" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Статус" %}</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">{% trans "На складе" %}</span>
{% elif equipment.status.code == 'assigned' %}<span class="badge badge-success">{% trans "Выдано" %}</span>
{% elif equipment.status.code == 'repair' %}<span class="badge badge-warning">{% trans "В ремонте" %}</span>
{% else %}<span class="badge badge-danger">{% trans "Списано" %}</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;">{% trans "Статус" %}</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>
{% if equipment.assigned_to_id %}
{% include "partials/it-equipment-assign-fields.html" with widget_id=equipment.id selected_target="employee" selected_location_id=equipment.location_id selected_employee_id=equipment.assigned_to_id require_target=False allow_empty=True %}
{% elif equipment.location_id and equipment.location.location_type == 'pharmacy' %}
{% include "partials/it-equipment-assign-fields.html" with widget_id=equipment.id selected_target="pharmacy" selected_location_id=equipment.location_id selected_employee_id=None require_target=False allow_empty=True %}
{% elif equipment.location_id %}
{% include "partials/it-equipment-assign-fields.html" with widget_id=equipment.id selected_target="office" selected_location_id=equipment.location_id selected_employee_id=None require_target=False allow_empty=True %}
{% else %}
{% include "partials/it-equipment-assign-fields.html" with widget_id=equipment.id selected_target="" selected_location_id=None selected_employee_id=None require_target=False allow_empty=True %}
{% endif %}
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Инв. №" %}</label>
<input type="text" name="inventory_number" value="{{ equipment.inventory_number|default:'' }}" class="input" style="min-width:9rem;">
</div>
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Дата покупки" %}</label>
<input type="date" name="purchase_date" value="{{ equipment.purchase_date|date:'Y-m-d' }}" class="input" style="min-width:9rem;">
</div>
<div>
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Гарантия до" %}</label>
<input type="date" name="warranty_until" value="{{ equipment.warranty_until|date:'Y-m-d' }}" class="input" style="min-width:9rem;">
</div>
<div style="flex-basis:100%;">
<label style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Примечания" %}</label>
<textarea name="notes" rows="2" class="input" style="width:100%; min-height:2.5rem; resize:vertical;">{{ equipment.notes }}</textarea>
</div>
<button type="submit" class="btn btn-primary">
{% trans "Сохранить" %}
<span class="btn-label-loading htmx-indicator">…</span>
</button>
{% if equipment.warranty_until %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); flex-basis:100%;">{% trans "Гарантия:" %} {{ equipment.warranty_status }} ({{ equipment.warranty_until|date:"d.m.Y" }})</div>
{% endif %}
</form>
<div style="margin-top:1rem; padding-top:0.75rem; border-top:1px solid var(--color-border);" onclick="event.stopPropagation();">
<div style="font-size:0.8125rem; font-weight:600; color:var(--color-foreground); margin-bottom:0.5rem;">{% trans "История перемещений" %}</div>
{% with history=equipment.assignments.all %}
{% if history %}
<ul style="list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:0.5rem;">
{% for a in history %}
<li style="font-size:0.8125rem; color:var(--color-foreground); display:flex; flex-wrap:wrap; gap:0.35rem 0.75rem; padding:0.375rem 0.5rem; background:var(--color-card); border-radius:var(--radius);">
<span style="color:var(--color-muted-foreground); white-space:nowrap;">{{ a.assigned_at|date:"d.m.Y H:i" }}</span>
<span>
{% if a.assigned_to %}{{ a.assigned_to.get_full_name|default:a.assigned_to.username }}{% endif %}
{% if a.assigned_to and a.location %} · {% endif %}
{% if a.location %}{{ a.location }}{% endif %}
{% if not a.assigned_to and not a.location %}—{% endif %}
</span>
{% if a.assigned_by %}
<span style="color:var(--color-muted-foreground);">{% trans "выдал" %}: {{ a.assigned_by.get_full_name|default:a.assigned_by.username }}</span>
{% endif %}
{% if a.returned_at %}
<span class="badge badge-muted">{% trans "возврат" %} {{ a.returned_at|date:"d.m.Y" }}</span>
{% else %}
<span class="badge badge-success">{% trans "открыта" %}</span>
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "Перемещений ещё не было" %}</div>
{% endif %}
{% endwith %}
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="7" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">
{% if equipment_filters_active %}
{% trans "Ничего не найдено — измените фильтры или сбросьте поиск" %}
{% else %}
{% trans "Оборудование ещё не добавлено" %}
{% endif %}
</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"{% if active_tab != 'tickets' %} style="display:none;"{% endif %}>
<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;">{% trans "Новые" %}</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;">{% trans "В работе" %}</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;">{% trans "Ожидание" %}</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;">{% trans "Решённые" %}</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;">{% trans "Просроченные" %}</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;">{% trans "№ / Тема" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Приоритет" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Заявитель" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Исполнитель" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Дата" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Статус" %}</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">{% trans "просрочено" %}</span>{% endif %}</div>
</td>
<td style="padding:0.75rem 1rem;">
{% if ticket.priority.code == 'critical' %}<span class="badge badge-danger">{% trans "Критический" %}</span>
{% elif ticket.priority.code == 'high' %}<span class="badge badge-warning">{% trans "Высокий" %}</span>
{% elif ticket.priority.code == 'medium' %}<span class="badge badge-info">{% trans "Средний" %}</span>
{% else %}<span class="badge badge-muted">{% trans "Низкий" %}</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">{% trans "Новая" %}</span>
{% elif ticket.status.code == 'in_progress' %}<span class="badge badge-warning">{% trans "В работе" %}</span>
{% elif ticket.status.code == 'waiting' %}<span class="badge badge-muted">{% trans "Ожидание" %}</span>
{% elif ticket.status.code == 'resolved' %}<span class="badge badge-success">{% trans "Решена" %}</span>
{% else %}<span class="badge badge-muted">{% trans "Закрыта" %}</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">{% trans "внутренний" %}</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;">{% trans "Статус" %}</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;">{% trans "Исполнитель" %}</label>
<select name="assignee_id" class="input" style="min-width:12rem;"
onclick="event.stopPropagation();" onmousedown="event.stopPropagation();">
<option value="">{% trans "— не назначено" %}</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>
{% empty %}
<option value="" disabled>{% trans "Нет сотрудников IT / staff — добавьте в группу IT" %}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">
{% trans "Сохранить" %}
<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="{% trans 'Комментарий...' %}" 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"> {% trans "внутренний" %}
</label>
<button type="submit" class="btn btn-secondary" style="border:1px solid var(--color-border);">
{% trans "Добавить" %}
<span class="btn-label-loading htmx-indicator">…</span>
</button>
</form>
<div style="margin-top:0.875rem; padding-top:0.875rem; border-top:1px solid var(--color-border);" onclick="event.stopPropagation();">
<div style="display:flex; align-items:center; justify-content:space-between; gap:0.75rem; margin-bottom:0.5rem; flex-wrap:wrap;">
<span style="font-size:0.8125rem; font-weight:500; color:var(--color-foreground);">
{% trans "Выполненные работы" %}
{% if ticket.worklogs_count %}<span class="badge badge-muted">{{ ticket.worklogs_count }}</span>{% endif %}
</span>
<button type="button" class="btn btn-primary" style="font-size:0.75rem; padding:0.3rem 0.65rem;"
onclick="itWorklogFromTicket({
id: {{ ticket.id }},
number: '{{ ticket.number|escapejs }}',
title: '{{ ticket.title|escapejs }}',
locationId: '{{ ticket.location_id|default:"" }}',
equipmentId: '{{ ticket.equipment_id|default:"" }}'
})">
{% trans "Добавить работу" %}
</button>
</div>
{% if ticket.work_logs.all %}
<div style="display:flex; flex-direction:column; gap:0.35rem;">
{% for log in ticket.work_logs.all %}
<div style="font-size:0.8125rem; background:var(--color-card); border:1px solid var(--color-border); border-radius:0.5rem; padding:0.5rem 0.75rem;">
<div style="display:flex; justify-content:space-between; gap:0.5rem; color:var(--color-muted-foreground); font-size:0.75rem;">
<span>
{{ log.date|date:"d.m.Y" }} · {{ log.technician.get_full_name|default:log.technician.username }}
{% if log.catalog_work %} · {{ log.catalog_work.parent.name|default:"" }}{% elif log.work_type %} · {{ log.work_type.name }}{% endif %}
</span>
<span>{% if log.hours_spent %}{{ log.hours_spent }} {% trans "ч" %}{% endif %}</span>
</div>
<div style="color:var(--color-foreground); margin-top:0.2rem;">{{ log.display_title|truncatechars:160 }}</div>
</div>
{% endfor %}
</div>
{% else %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "К заявке ещё не привязаны работы" %}</div>
{% endif %}
</div>
</td>
</tr>
{% empty %}
<tr><td colspan="7" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">{% trans "Заявок пока нет" %}</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"{% if active_tab != 'worklog' %} style="display:none;"{% endif %}>
<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;">
{% if worklog_month_id != 'all' %}{% trans "Записей за" %} {{ worklog_stats_label }}{% else %}{% trans "Записей в этом месяце" %}{% endif %}
</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;">
{% if worklog_month_id != 'all' %}{% trans "Часов за" %} {{ worklog_stats_label }}{% else %}{% trans "Часов в этом месяце" %}{% endif %}
</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:space-between; align-items:flex-end; gap:1rem; flex-wrap:wrap; margin-bottom:1rem;">
<form id="it-worklog-filters"
hx-get="/it-manager/"
hx-target="#main-content"
hx-push-url="true"
hx-indicator="#loader"
hx-trigger="change"
style="display:flex; align-items:flex-end; gap:0.75rem; flex-wrap:wrap; margin:0;">
<input type="hidden" name="tab" value="worklog">
<div>
<label for="it-worklog-filter-month" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Месяц" %}</label>
<select id="it-worklog-filter-month" name="worklog_month" class="input" style="min-width:12rem; width:auto;">
<option value="all" {% if worklog_month_id == 'all' %}selected{% endif %}>{% trans "Все месяцы" %}</option>
{% for mid, label in worklog_month_choices %}
<option value="{{ mid }}" {% if worklog_month_id == mid %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="it-worklog-filter-tech" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Сотрудник" %}</label>
<select id="it-worklog-filter-tech" name="worklog_technician" class="input" style="min-width:14rem; width:auto;">
<option value="">{% trans "Все сотрудники" %}</option>
{% for emp in worklog_technicians %}
<option value="{{ emp.pk }}" {% if worklog_technician_id == emp.pk %}selected{% endif %}>
{{ emp.get_full_name|default:emp.username }}
</option>
{% endfor %}
</select>
</div>
<div>
<label for="it-worklog-filter-cat" style="display:block; font-size:0.75rem; font-weight:500; color:var(--color-muted-foreground); margin-bottom:0.25rem;">{% trans "Категория" %}</label>
<select id="it-worklog-filter-cat" name="worklog_category" class="input" style="min-width:14rem; width:auto;">
<option value="">{% trans "Все категории" %}</option>
{% for cat in it_work_catalog.categories %}
<option value="{{ cat.id }}" {% if worklog_category_id == cat.id %}selected{% endif %}>{{ cat.name }}</option>
{% endfor %}
</select>
</div>
{% if it_can_edit_worklogs %}
<p style="font-size:0.75rem; color:var(--color-muted-foreground); margin:0 0 0.5rem; max-width:20rem;">
{% trans "Руководитель: можно менять типовую работу, комментарий и удалять записи. Сохранение — при смене поля." %}
</p>
{% endif %}
</form>
<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>
{% trans "Добавить запись" %}
</button>
</div>
{% if it_worklog_message %}
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; border:1px solid hsl(152 40% 70%); background:color-mix(in srgb, var(--color-success) 12%, var(--color-card)); color:var(--color-foreground); font-size:0.875rem;">
{{ it_worklog_message }}
</div>
{% endif %}
{% if it_worklog_error %}
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; border:1px solid color-mix(in srgb, var(--color-destructive) 40%, var(--color-border)); background:color-mix(in srgb, var(--color-destructive) 10%, var(--color-card)); color:var(--color-foreground); font-size:0.875rem;">
{{ it_worklog_error }}
</div>
{% endif %}
<!-- Виїзна панель: новий запис про виконану роботу -->
<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);">{% trans "Добавить запись о выполненной работе" %}</span>
<button type="button" onclick="itPanelClose('it-worklog-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
<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>
{{ it_work_catalog|json_script:"it-work-catalog-data" }}
<div style="padding:1.25rem; display:flex; flex-direction:column; gap:1rem;">
<div id="it-worklog-ticket-hint" style="display:none; padding:0.625rem 0.75rem; border-radius:0.5rem; background:color-mix(in srgb, var(--color-primary) 8%, var(--color-card)); border:1px solid color-mix(in srgb, var(--color-primary) 25%, var(--color-border)); font-size:0.8125rem; 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;">{% trans "Дата" %}</label>
<input type="date" name="date" id="it-worklog-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;">{% trans "Категория" %} <span style="color:var(--color-destructive);">*</span></label>
<select id="it-worklog-category" class="input" style="width:100%;" onchange="itWorklogCategoryChanged()">
<option value="">{% trans "— Выберите категорию —" %}</option>
{% for cat in it_work_catalog.categories %}
<option value="{{ cat.id }}">{{ cat.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;">{% trans "Типовая работа" %} <span style="color:var(--color-destructive);">*</span></label>
<select name="catalog_work_id" id="it-worklog-work" required class="input" style="width:100%;" onchange="itWorklogWorkChanged()">
<option value="">{% trans "— Сначала выберите категорию —" %}</option>
</select>
<div id="it-worklog-work-notes" style="display:none; font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.375rem;"></div>
</div>
<div id="it-worklog-details" style="display:none; flex-direction:column; gap:0.75rem;"></div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Заявка" %}</label>
<div class="searchable-select" data-placeholder="{% trans 'Поиск заявки по номеру или теме...' %}">
<select name="ticket_id" id="it-worklog-ticket" hidden>
<option value="">—</option>
{% for ticket in worklog_tickets %}
<option value="{{ ticket.id }}"
data-location="{{ ticket.location_id|default:'' }}"
data-equipment="{{ ticket.equipment_id|default:'' }}"
data-title="{{ ticket.title }}">
{{ ticket.number }} — {{ ticket.title }}{% if ticket.status.code == 'closed' or ticket.status.code == 'resolved' %} ({{ ticket.status.name }}){% endif %}
</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;">{% trans "Локация" %}</label>
<div class="searchable-select" data-placeholder="{% trans 'Поиск: А3, П10, организация, адрес...' %}">
<select name="location_id" id="it-worklog-location" hidden>
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}" data-search="{{ location.search_text }}">{{ 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;">{% trans "Затрачено часов" %}</label>
<input type="number" step="0.5" min="0" name="hours_spent" id="it-worklog-hours" 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;">{% trans "Оборудование" %}</label>
<select name="equipment_id" id="it-worklog-equipment" 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;">{% trans "Комментарий" %} <span style="font-weight:400; color:var(--color-muted-foreground);">{% trans "(необязательно)" %}</span></label>
<textarea name="description" id="it-worklog-description" 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>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Результат" %}</label>
<textarea name="result" id="it-worklog-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;">
{% trans "Добавить запись" %}
<span class="btn-label-loading htmx-indicator">{% trans "Сохранение…" %}</span>
</button>
</div>
</div>
</form>
</div>
<!-- Журнал -->
{% if it_can_edit_worklogs %}
{% for log in worklogs_page %}
<form id="worklog-form-{{ log.pk }}"
hx-post="/it-manager/worklog/{{ log.pk }}/update/"
hx-target="#worklog-status-{{ log.pk }}"
hx-swap="innerHTML"
style="display:none;">{% csrf_token %}</form>
{% endfor %}
{% endif %}
<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;">{% trans "Дата" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Исполнитель" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Заявка" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Типовая работа" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Комментарий" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Локация" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Часов" %}</th>
{% if it_can_edit_worklogs %}
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Результат" %}</th>
<th style="padding:0.75rem 0.5rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;"></th>
{% endif %}
</tr>
</thead>
<tbody>
{% for log in worklogs_page %}
{% if it_can_edit_worklogs %}
<tr style="border-bottom:1px solid var(--color-border); vertical-align:top;">
<td style="padding:0.5rem 0.75rem; white-space:nowrap;">
<input form="worklog-form-{{ log.pk }}" type="date" name="date"
value="{{ log.date|date:'Y-m-d' }}" class="input"
style="width:9.5rem; font-size:0.8125rem; padding:0.3rem 0.4rem;"
onchange="this.form.requestSubmit()">
</td>
<td style="padding:0.5rem 0.75rem;">
<select form="worklog-form-{{ log.pk }}" name="technician_id" class="input"
style="min-width:9rem; max-width:12rem; font-size:0.8125rem; padding:0.3rem 0.4rem;"
onchange="this.form.requestSubmit()">
{% for emp in worklog_technicians %}
<option value="{{ emp.pk }}" {% if log.technician_id == emp.pk %}selected{% endif %}>
{{ emp.get_full_name|default:emp.username }}
</option>
{% endfor %}
</select>
</td>
<td style="padding:0.5rem 0.75rem; color:var(--color-muted-foreground); font-size:0.8125rem; white-space:nowrap;">
{% if log.ticket %}
<button type="button" class="btn btn-ghost" style="padding:0; font-size:0.8125rem; color:var(--color-primary);"
onclick="itTabSwitch('tickets'); itToggleRow('ticket-{{ log.ticket_id }}');"
title="{{ log.ticket.title }}">{{ log.ticket.number }}</button>
{% else %}—{% endif %}
</td>
<td style="padding:0.5rem 0.75rem; min-width:14rem; max-width:18rem;">
{% if log.catalog_work %}
<select id="it-worklog-row-cat-{{ log.pk }}" class="input"
style="width:100%; font-size:0.75rem; padding:0.25rem 0.35rem; margin-bottom:0.25rem;"
onchange="itWorklogRowCategoryChanged({{ log.pk }})">
{% for cat in it_work_catalog.categories %}
<option value="{{ cat.id }}" {% if log.catalog_work.parent_id == cat.id %}selected{% endif %}>{{ cat.name }}</option>
{% endfor %}
</select>
<select form="worklog-form-{{ log.pk }}" name="catalog_work_id"
id="it-worklog-row-work-{{ log.pk }}" class="input"
style="width:100%; font-size:0.8125rem; padding:0.3rem 0.4rem;"
onchange="itWorklogRowWorkChanged({{ log.pk }}, true)">
{% for w in it_work_catalog.works %}
{% if w.category_id == log.catalog_work.parent_id %}
<option value="{{ w.id }}" {% if w.id == log.catalog_work_id %}selected{% endif %}>{{ w.name }}</option>
{% endif %}
{% endfor %}
</select>
<div id="it-worklog-row-details-{{ log.pk }}" style="display:flex; flex-direction:column; gap:0.25rem; margin-top:0.375rem;">
{% with req=log.catalog_work.extra_data.required_details %}
{% if req %}
{% for key in req %}
<label style="font-size:0.6875rem; color:var(--color-muted-foreground);">
{{ worklog_detail_labels|get_item:key|default:key }}
<input form="worklog-form-{{ log.pk }}" type="text" name="detail_{{ key }}"
value="{{ log.details|get_item:key }}"
class="input" style="width:100%; font-size:0.75rem; padding:0.2rem 0.35rem; margin-top:0.1rem;"
onchange="this.form.requestSubmit()">
</label>
{% endfor %}
{% endif %}
{% endwith %}
</div>
{% else %}
<span class="badge badge-muted" style="margin-bottom:0.25rem;">{% trans "без справочника" %}</span>
<select form="worklog-form-{{ log.pk }}" name="work_type" class="input"
style="min-width:8rem; max-width:11rem; font-size:0.8125rem; padding:0.3rem 0.4rem; display:block; margin-bottom:0.35rem;"
onchange="this.form.requestSubmit()">
{% for value, label in worklog_types %}
<option value="{{ value }}" {% if log.work_type_id and log.work_type.code == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<select id="it-worklog-row-cat-{{ log.pk }}" class="input"
style="width:100%; font-size:0.75rem; padding:0.25rem 0.35rem; margin-bottom:0.25rem;"
onchange="itWorklogRowCategoryChanged({{ log.pk }})">
<option value="">{% trans "— или выбрать типовую —" %}</option>
{% for cat in it_work_catalog.categories %}
<option value="{{ cat.id }}">{{ cat.name }}</option>
{% endfor %}
</select>
<select form="worklog-form-{{ log.pk }}" name="catalog_work_id"
id="it-worklog-row-work-{{ log.pk }}" class="input"
style="width:100%; font-size:0.8125rem; padding:0.3rem 0.4rem;"
onchange="itWorklogRowWorkChanged({{ log.pk }}, true)">
<option value="">{% trans "—" %}</option>
</select>
<div id="it-worklog-row-details-{{ log.pk }}" style="display:flex; flex-direction:column; gap:0.25rem; margin-top:0.375rem;"></div>
{% endif %}
</td>
<td style="padding:0.5rem 0.75rem; min-width:14rem;">
<textarea form="worklog-form-{{ log.pk }}" name="description" rows="2"
class="input" style="width:100%; min-width:12rem; font-size:0.8125rem; padding:0.3rem 0.4rem; resize:vertical;"
onchange="this.form.requestSubmit()">{{ log.description }}</textarea>
</td>
<td style="padding:0.5rem 0.75rem;">
<select form="worklog-form-{{ log.pk }}" name="location_id" class="input"
style="min-width:10rem; max-width:14rem; font-size:0.8125rem; padding:0.3rem 0.4rem;"
onchange="this.form.requestSubmit()">
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}" {% if log.location_id == location.id %}selected{% endif %}>{{ location }}</option>
{% endfor %}
</select>
</td>
<td style="padding:0.5rem 0.75rem;">
<input form="worklog-form-{{ log.pk }}" type="number" step="0.5" min="0" name="hours_spent"
value="{{ log.hours_spent|default_if_none:'' }}" class="input"
style="width:4.5rem; font-size:0.8125rem; padding:0.3rem 0.4rem;"
onchange="this.form.requestSubmit()">
</td>
<td style="padding:0.5rem 0.75rem; min-width:10rem;">
<textarea form="worklog-form-{{ log.pk }}" name="result" rows="2"
class="input" style="width:100%; font-size:0.8125rem; padding:0.3rem 0.4rem; resize:vertical;"
onchange="this.form.requestSubmit()">{{ log.result }}</textarea>
</td>
<td style="padding:0.5rem 0.5rem; white-space:nowrap;">
<div style="display:flex; flex-direction:column; align-items:flex-start; gap:0.35rem;">
<span id="worklog-status-{{ log.pk }}" aria-live="polite"></span>
<button type="button"
class="btn btn-ghost"
style="padding:0.2rem 0.4rem; font-size:0.75rem; color:var(--color-destructive);"
title="{% trans 'Удалить запись' %}"
hx-post="/it-manager/worklog/{{ log.pk }}/delete/"
hx-confirm="{% trans 'Удалить эту запись о работе?' %}"
hx-target="closest tr"
hx-swap="outerHTML">
{% trans "Удалить" %}
</button>
</div>
</td>
</tr>
{% else %}
<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); font-size:0.8125rem; white-space:nowrap;">
{% if log.ticket %}
<button type="button" class="btn btn-ghost" style="padding:0; font-size:0.8125rem; color:var(--color-primary);"
onclick="itTabSwitch('tickets'); itToggleRow('ticket-{{ log.ticket_id }}');"
title="{{ log.ticket.title }}">{{ log.ticket.number }}</button>
{% else %}—{% endif %}
</td>
<td style="padding:0.625rem 1rem; color:var(--color-foreground); max-width:16rem;">
{% if log.catalog_work %}
<div>{{ log.catalog_work.name }}</div>
<div style="font-size:0.75rem; color:var(--color-muted-foreground);">{{ log.catalog_work.parent.name|default:"" }}</div>
{% if log.details %}
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.2rem;">
{% for k, v in log.details.items %}{% if v %}{{ worklog_detail_labels|get_item:k|default:k }}: {{ v }}{% if not forloop.last %}; {% endif %}{% endif %}{% endfor %}
</div>
{% endif %}
{% else %}
<span class="badge badge-muted">{% trans "без справочника" %}</span>
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{% if log.work_type %}{{ log.work_type.name }}{% endif %}</div>
{% endif %}
</td>
<td style="padding:0.625rem 1rem; color:var(--color-foreground); max-width:22rem;">
{% if log.catalog_work %}
{{ log.description|truncatechars:120|default:"—" }}
{% else %}
{{ log.description|truncatechars:120 }}
{% endif %}
</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>
{% endif %}
{% empty %}
<tr><td colspan="{% if it_can_edit_worklogs %}9{% else %}7{% endif %}" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">{% trans "Записей ещё нет" %}</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"{% if active_tab != 'consumables' %} style="display:none;"{% endif %}>
<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;">{% trans "Всего позиций" %}</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;">{% trans "Заканчивается / на замену" %}</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>
{% trans "Добавить материал" %}
</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);">{% trans "Добавить расходный материал" %}</span>
<button type="button" onclick="itPanelClose('it-consumable-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
<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;">{% trans "Тип" %} <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__">{% trans "+ Добавить новый тип..." %}</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Цвет" %}</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__">{% trans "+ Добавить новый цвет..." %}</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Производитель" %}</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;">{% trans "Модель / артикул" %} <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;">{% trans "Принтер" %}</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;">{% trans "Локация хранения" %}</label>
<div class="searchable-select" data-placeholder="{% trans 'Поиск по адресу или номеру аптеки...' %}">
<select name="location_id" hidden>
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}" data-search="{{ location.search_text }}">{{ 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;">{% trans "Ресурс (страниц)" %}</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;">{% trans "Дата покупки" %}</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;">{% trans "Примечания" %}</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;">
{% trans "Добавить" %}
<span class="btn-label-loading htmx-indicator">{% trans "Сохранение…" %}</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;">{% trans "Тип / Модель" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Цвет" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Принтер" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Статус" %}</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;">{% trans "Статус" %}</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">
{% trans "Сохранить" %}
<span class="btn-label-loading htmx-indicator">…</span>
</button>
{% if consumable.page_yield %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "Ресурс:" %} {{ consumable.page_yield }} {% trans "стр." %}</div>
{% endif %}
{% if consumable.notes %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); flex-basis:100%;">{% trans "Примечания:" %} {{ consumable.notes }}</div>
{% endif %}
</form>
</td>
</tr>
{% empty %}
<tr><td colspan="5" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">{% trans "Расходных материалов ещё не добавлено" %}</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"{% if active_tab != 'providers' %} style="display:none;"{% endif %}>
<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;">{% trans "Провайдеров" %}</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;">{% trans "Договоров" %}</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;">{% trans "Заканчиваются через 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>
{% trans "Добавить провайдера" %}
</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>
{% trans "Добавить договор" %}
</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);">{% trans "Провайдеры" %}</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;">{% trans "Провайдеров ещё нет" %}</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);">{% trans "Новый провайдер" %}</span>
<button type="button" onclick="itPanelClose('it-provider-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
<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;">{% trans "Название" %} <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;">{% trans "Телефон" %}</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;">{% trans "Сайт" %}</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;">{% trans "Телефон техподдержки" %}</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;">{% trans "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;">{% trans "Примечания" %}</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;">
{% trans "Добавить провайдера" %}
<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);">{% trans "Новый договор" %}</span>
<button type="button" onclick="itPanelClose('it-contract-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
<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;">{% trans "Провайдер" %} <span style="color:var(--color-destructive);">*</span></label>
<select name="provider_id" required class="input" style="width:100%;" id="it-contract-provider-select" onchange="itContractFilterParents()">
<option value="">—</option>
{% for provider in providers %}
<option value="{{ provider.id }}">{{ provider.name }}</option>
{% endfor %}
</select>
</div>
<div id="it-contract-location-wrap">
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">
{% trans "Локация" %} <span id="it-contract-location-required" style="color:var(--color-destructive);">*</span>
</label>
<div class="searchable-select" data-placeholder="{% trans 'Поиск по адресу или номеру аптеки...' %}">
<select name="location_id" id="it-contract-location-select" required hidden>
<option value="">—</option>
{% for location in it_locations %}
<option value="{{ location.id }}" data-search="{{ location.search_text }}">{{ location }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<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="is_framework" id="it-contract-is-framework" onchange="itContractFrameworkToggle(this.checked)">
{% trans "Общий (рамочный) договор" %}
</label>
<p style="font-size:0.75rem; color:var(--color-muted-foreground); margin:0.35rem 0 0;">{% trans "Например, 708052 — к нему привязываются дочерние 70805208, 70805206… Локация для такого договора не нужна." %}</p>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Номер договора" %} <span style="color:var(--color-destructive);">*</span></label>
<input type="text" name="contract_number" required class="input" style="width:100%;">
</div>
<div id="it-contract-parent-wrap">
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Общий договор" %}</label>
<select name="parent_contract_id" id="it-contract-parent-select" class="input" style="width:100%;">
<option value="">— {% trans "нет" %} —</option>
{% for fc in framework_contracts %}
<option value="{{ fc.pk }}" data-provider="{{ fc.provider_id }}">№{{ fc.contract_number }} · {{ fc.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;">{% trans "Тип услуги" %} <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__">{% trans "+ Добавить новый тип..." %}</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Технология подключения" %}</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__">{% trans "+ Добавить новую технологию..." %}</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Дата начала" %} <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;">{% trans "Дата окончания" %}</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;">{% trans "Стоимость/мес." %}</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;">{% trans "Скорость ↓ Мбит/с" %}</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;">{% trans "Скорость ↑ Мбит/с" %}</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;">{% trans "Лицевой счёт" %}</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'">
{% trans "Выделенный 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;">{% trans "IP-адреса" %}</label>
<textarea name="static_ips" placeholder="{% trans 'По одному 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;">{% trans "Примечания" %}</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;">
{% trans "Добавить договор" %}
<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;">{% trans "Провайдер / Локация" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Тип услуги" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Скорость" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Окончание" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Статус" %}</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>
{% if contract.is_framework %}<span class="badge badge-info" style="font-size:0.6875rem; margin-left:0.35rem;">{% trans "Общий" %}</span>{% endif %}
<span style="font-size:0.75rem; color:var(--color-muted-foreground);"> №{{ contract.contract_number }}</span>
{% if contract.parent_contract %}
<span style="font-size:0.6875rem; color:var(--color-muted-foreground);"> · {% trans "к" %} №{{ contract.parent_contract.contract_number }}</span>
{% endif %}
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ contract.location_display }}</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;">{% trans "Статус" %}</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">
{% trans "Сохранить" %}
<span class="btn-label-loading htmx-indicator">…</span>
</button>
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "Счёт:" %} {{ contract.account_number|default:"—" }} · {{ contract.monthly_cost|default:"—" }} {% trans "грн/мес" %}</div>
{% if contract.child_contracts.all %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); margin-top:0.35rem;">
{% trans "Дочерние:" %}
{% for child in contract.child_contracts.all %}№{{ child.contract_number }}{% if not forloop.last %}, {% endif %}{% endfor %}
</div>
{% endif %}
</form>
</td>
</tr>
{% empty %}
<tr><td colspan="6" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">{% trans "Договоров ещё нет" %}</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"{% if active_tab != 'servicecalls' %} style="display:none;"{% endif %}>
<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 }} {% trans "обращений" %}</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>
{% trans "Новое обращение" %}
</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);">{% trans "Новое обращение" %}</span>
<button type="button" onclick="itPanelClose('it-servicecall-panel')" class="btn btn-ghost btn-icon" aria-label="{% trans 'Закрыть' %}">
<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;">{% trans "Кто обратился" %} <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;">{% trans "Канал" %} <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__">{% trans "+ Добавить новый канал..." %}</option>
</select>
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; color:var(--color-foreground); margin-bottom:0.375rem;">{% trans "Затрачено минут" %}</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;">{% trans "Описание обращения" %} <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;">{% trans "Решение" %}</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;">
{% trans "Добавить обращение" %}
<span class="btn-label-loading htmx-indicator">{% trans "Сохранение…" %}</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;">{% trans "Дата" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Кто обратился" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Канал" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Принял" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Описание" %}</th>
<th style="padding:0.75rem 1rem;text-align:left;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Длительность" %}</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);">{% trans "Обращений ещё нет" %}</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>
<!-- ══ /ВКЛАДКА: ОБРАЩЕННЯ ══ -->
<script>initSearchableSelects(document);</script>
</div>
{% endwith %}