3e969e29dc
Модель и сервис событий календаря, вью и страница календаря. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
112 lines
9.8 KiB
HTML
112 lines
9.8 KiB
HTML
{% load common_tags %}
|
|
{% load i18n %}
|
|
{% if not accounting_embed %}<div class="page-content" id="timetrack-page">{% else %}<div id="timetrack-page">{% endif %}
|
|
|
|
{% if not accounting_embed %}
|
|
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;">
|
|
<div>
|
|
<h1 style="font-size:1.25rem;font-weight:500;color:var(--color-foreground);">{% trans "Учёт рабочего времени" %}</h1>
|
|
<p style="font-size:0.875rem;color:var(--color-muted-foreground);margin-top:0.25rem;">
|
|
{{ month_label }} · {{ stats.employees }} {% trans "сотрудников с отметками" %}
|
|
</p>
|
|
</div>
|
|
<!-- Вибір місяця -->
|
|
<div style="display:flex;align-items:center;gap:0.5rem;">
|
|
<a href="#" class="btn btn-ghost btn-icon"
|
|
hx-get="{{ accounting_base_url|default:'/timetrack/' }}?month={{ prev_month }}{% if location_type %}&location_type={{ location_type }}{% endif %}"
|
|
hx-target="#main-content" hx-push-url="true" hx-indicator="#loader" title="{% trans 'Предыдущий месяц' %}">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
|
|
</a>
|
|
<span style="font-size:0.875rem;font-weight:500;color:var(--color-foreground);min-width:9rem;text-align:center;">{{ month_label }}</span>
|
|
<a href="#" class="btn btn-ghost btn-icon"
|
|
hx-get="{{ accounting_base_url|default:'/timetrack/' }}?month={{ next_month }}{% if location_type %}&location_type={{ location_type }}{% endif %}"
|
|
hx-target="#main-content" hx-push-url="true" hx-indicator="#loader" title="{% trans 'Следующий месяц' %}">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div style="display:flex;align-items:center;justify-content:flex-end;margin-bottom:1rem;gap:0.5rem;">
|
|
<a href="#" class="btn btn-ghost btn-icon"
|
|
hx-get="{{ accounting_base_url }}&month={{ prev_month }}{% if location_type %}&location_type={{ location_type }}{% endif %}"
|
|
hx-target="#main-content" hx-push-url="true" hx-indicator="#loader" title="{% trans 'Предыдущий месяц' %}">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
|
|
</a>
|
|
<span style="font-size:0.875rem;font-weight:500;color:var(--color-foreground);min-width:9rem;text-align:center;">{{ month_label }} · {{ stats.employees }} {% trans "сотр." %}</span>
|
|
<a href="#" class="btn btn-ghost btn-icon"
|
|
hx-get="{{ accounting_base_url }}&month={{ next_month }}{% if location_type %}&location_type={{ location_type }}{% endif %}"
|
|
hx-target="#main-content" hx-push-url="true" hx-indicator="#loader" title="{% trans 'Следующий месяц' %}">
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Метрики -->
|
|
<div style="display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:0.75rem;margin-bottom:1.5rem;">
|
|
{% for m in metrics %}
|
|
<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;">{{ m.label }}</div>
|
|
<div style="font-size:1.5rem;font-weight:500;color:{{ m.color }};">{{ m.value }}</div>
|
|
<div style="font-size:0.75rem;color:var(--color-muted-foreground);margin-top:0.25rem;">{{ m.hint }}</div>
|
|
</div>
|
|
{% endfor %}
|
|
</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);">
|
|
|
|
<!-- Фільтр за типом локації -->
|
|
<div style="padding:0.875rem 1.5rem;border-bottom:1px solid var(--color-border);">
|
|
<div style="display:inline-flex;gap:0.25rem;background:var(--color-muted);border-radius:var(--radius);padding:0.25rem;">
|
|
<a href="#" {% if accounting_embed %}hx-get="{{ accounting_base_url }}&month={{ month }}"{% else %}hx-get="/timetrack/?month={{ month }}"{% endif %} hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
|
|
style="display:inline-flex;align-items:center;padding:0.25rem 0.875rem;font-size:0.8125rem;border-radius:calc(var(--radius) - 2px);font-weight:500;text-decoration:none;transition:all 150ms;{% if not location_type %}background:var(--color-card);color:var(--color-card-foreground);box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}color:var(--color-muted-foreground);{% endif %}">{% trans "Все" %} · {{ counts.all }}</a>
|
|
<a href="#" {% if accounting_embed %}hx-get="{{ accounting_base_url }}&month={{ month }}&location_type=office"{% else %}hx-get="/timetrack/?month={{ month }}&location_type=office"{% endif %} hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
|
|
style="display:inline-flex;align-items:center;padding:0.25rem 0.875rem;font-size:0.8125rem;border-radius:calc(var(--radius) - 2px);font-weight:500;text-decoration:none;transition:all 150ms;{% if location_type == 'office' %}background:var(--color-card);color:var(--color-card-foreground);box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}color:var(--color-muted-foreground);{% endif %}">{% trans "Офис" %} · {{ counts.office }}</a>
|
|
<a href="#" {% if accounting_embed %}hx-get="{{ accounting_base_url }}&month={{ month }}&location_type=pharmacy"{% else %}hx-get="/timetrack/?month={{ month }}&location_type=pharmacy"{% endif %} hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
|
|
style="display:inline-flex;align-items:center;padding:0.25rem 0.875rem;font-size:0.8125rem;border-radius:calc(var(--radius) - 2px);font-weight:500;text-decoration:none;transition:all 150ms;{% if location_type == 'pharmacy' %}background:var(--color-card);color:var(--color-card-foreground);box-shadow:0 1px 2px rgb(0 0 0/0.08);{% else %}color:var(--color-muted-foreground);{% endif %}">{% trans "Аптеки" %} · {{ counts.pharmacy }}</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Таблиця -->
|
|
<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:right;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Часов" %}</th>
|
|
<th style="padding:0.75rem 1rem;text-align:right;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Дней" %}</th>
|
|
<th style="padding:0.75rem 1rem;text-align:right;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Сред./день" %}</th>
|
|
<th style="padding:0.75rem 1rem;text-align:right;color:var(--color-muted-foreground);font-weight:600;font-size:0.8125rem;">{% trans "Незакрытых" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in page %}
|
|
<tr class="tr-hover" style="border-bottom:1px solid var(--color-border);cursor:pointer;transition:background 150ms;"
|
|
hx-get="/employees/{{ row.employee_id }}/" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader">
|
|
<td style="padding:0.875rem 1rem;vertical-align:middle;font-weight:500;color:var(--color-card-foreground);">{{ row.name }}</td>
|
|
<td style="padding:0.875rem 1rem;vertical-align:middle;text-align:right;color:var(--color-card-foreground);">{{ row.hours }}</td>
|
|
<td style="padding:0.875rem 1rem;vertical-align:middle;text-align:right;color:var(--color-muted-foreground);">{{ row.days }}</td>
|
|
<td style="padding:0.875rem 1rem;vertical-align:middle;text-align:right;color:var(--color-muted-foreground);">{{ row.avg }}</td>
|
|
<td style="padding:0.875rem 1rem;vertical-align:middle;text-align:right;">
|
|
{% if row.incomplete %}
|
|
<span class="badge badge-warning">{{ row.incomplete }}</span>
|
|
{% else %}
|
|
<span style="color:var(--color-muted-foreground);">—</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="5" style="padding:2rem 1.25rem;text-align:center;color:var(--color-muted-foreground);">
|
|
{% trans "Нет отметок рабочего времени за" %} {{ month_label }}.
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{% trans "сотрудников" as tt_item_label %}
|
|
{% include "partials/pagination.html" with page=page base_url=pagination_base_url|default:"/timetrack/" page_param="page" size_param="per_page" item_label=tt_item_label %}
|
|
</div>
|
|
</div>
|