3359a8db13
Модель/сервисы HR-заявок с заменами, приглашения на установку пароля (инвайты), обновлённая страница профиля сотрудника и правки 2FA. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
100 lines
9.3 KiB
HTML
100 lines
9.3 KiB
HTML
{% load i18n %}
|
||
<div id="emp-profile-hr-requests" 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="padding:0.875rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; gap:0.75rem; flex-wrap:wrap;">
|
||
<span style="font-size:0.9375rem; font-weight:600; color:var(--color-foreground);">{% trans "Заявки и отпуска" %}</span>
|
||
<div style="display:flex; gap:0.375rem; flex-wrap:wrap;">
|
||
<button type="button" onclick="empProfileShowRequestForm('vacation', '{% trans "Отпуск" %}')" class="btn btn-secondary emp-hr-type-btn" data-request-type="vacation" data-request-label="{% trans "Отпуск" %}" style="font-size:0.75rem; padding:0.35rem 0.625rem;">{% trans "Отпуск" %}</button>
|
||
<button type="button" onclick="empProfileShowRequestForm('additional_vacation', '{% trans "Доп. отпуск" %}')" class="btn btn-secondary emp-hr-type-btn" data-request-type="additional_vacation" data-request-label="{% trans "Доп. отпуск" %}" style="font-size:0.75rem; padding:0.35rem 0.625rem;">{% trans "Доп." %}</button>
|
||
<button type="button" onclick="empProfileShowRequestForm('certificate', '{% trans "Справка" %}')" class="btn btn-secondary emp-hr-type-btn" data-request-type="certificate" data-request-label="{% trans "Справка" %}" style="font-size:0.75rem; padding:0.35rem 0.625rem;">{% trans "Справка" %}</button>
|
||
<button type="button" onclick="empProfileShowRequestForm('sick_leave', '{% trans "Больничный" %}')" class="btn btn-secondary emp-hr-type-btn" data-request-type="sick_leave" data-request-label="{% trans "Больничный" %}" style="font-size:0.75rem; padding:0.35rem 0.625rem;">{% trans "Больничный" %}</button>
|
||
<button type="button" onclick="empProfileShowRequestForm('day_off', '{% trans "Отгул" %}')" class="btn btn-secondary emp-hr-type-btn" data-request-type="day_off" data-request-label="{% trans "Отгул" %}" style="font-size:0.75rem; padding:0.35rem 0.625rem;">{% trans "Отгул" %}</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="emp-hr-request-form-wrap" style="{% if hr_request_form_open %}display:block;{% else %}display:none;{% endif %} padding:0 1.25rem 1rem; border-bottom:1px solid var(--color-border);">
|
||
<form hx-post="{% url 'hr_request_create' %}" hx-target="#main-content" hx-indicator="#loader" novalidate
|
||
style="border:1px solid var(--color-border); border-radius:0.625rem; overflow:hidden; margin-top:0.75rem;">
|
||
{% csrf_token %}
|
||
<input type="hidden" name="return_to" value="profile">
|
||
<input type="hidden" name="request_type" id="emp-hr-request-type" value="{{ hr_request_form.type|default:'vacation' }}">
|
||
<div style="padding:0.75rem 1rem; border-bottom:1px solid var(--color-border); display:flex; justify-content:space-between; align-items:center; gap:0.5rem;">
|
||
<span style="font-size:0.8125rem; font-weight:500;"><span id="emp-hr-request-type-label">{% if hr_request_form.type %}{% for value, label in hr_request_types %}{% if hr_request_form.type == value %}{{ label }}{% endif %}{% endfor %}{% else %}{% trans "Новая заявка" %}{% endif %}</span></span>
|
||
<button type="button" class="btn btn-ghost" style="font-size:0.75rem;" onclick="empProfileHideRequestForm()">{% trans "Закрыть" %}</button>
|
||
</div>
|
||
<div style="padding:1rem; display:grid; grid-template-columns:repeat(auto-fit, minmax(10rem, 1fr)); gap:0.75rem; align-items:end;">
|
||
<div id="emp-hr-request-dates-wrap">
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Дата с" %}</label>
|
||
<input type="date" name="date_from" id="emp-hr-request-date-from" class="input" style="width:100%;" value="{{ hr_request_form.date_from|default:'' }}">
|
||
</div>
|
||
<div id="emp-hr-request-date-to-wrap">
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Дата по" %}</label>
|
||
<input type="date" name="date_to" id="emp-hr-request-date-to" class="input" style="width:100%;" value="{{ hr_request_form.date_to|default:'' }}">
|
||
</div>
|
||
<div style="grid-column:1 / -1;">
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Комментарий" %}</label>
|
||
<textarea name="note" rows="2" class="input" style="width:100%; resize:vertical;">{{ hr_request_form.note|default:'' }}</textarea>
|
||
</div>
|
||
</div>
|
||
<div style="padding:0.75rem 1rem; border-top:1px solid var(--color-border); text-align:right;">
|
||
<button type="submit" class="btn btn-primary" style="font-size:0.8125rem;">{% trans "Отправить" %}</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div style="display:grid; grid-template-columns:1fr 1fr; gap:0; border-top:1px solid var(--color-border);">
|
||
<div style="border-right:1px solid var(--color-border);">
|
||
<div style="padding:0.75rem 1.25rem; border-bottom:1px solid var(--color-border); font-size:0.8125rem; font-weight:500;">{% trans "Мои заявки" %}</div>
|
||
{% for req in my_hr_requests|slice:":8" %}
|
||
<div style="padding:0.75rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; justify-content:space-between; gap:0.5rem;">
|
||
<div style="min-width:0;">
|
||
<div style="font-size:0.8125rem; font-weight:500;">{{ req.summary }}</div>
|
||
<div style="font-size:0.75rem; color:var(--color-muted-foreground);">{{ req.created_at|date:"d.m.Y" }}{% if req.day_count %} · {{ req.day_count }} {% trans "дн." %}{% endif %}</div>
|
||
</div>
|
||
<div style="display:flex; align-items:center; gap:0.375rem; flex-shrink:0;">
|
||
{% if req.status == 'pending' %}
|
||
<span class="badge badge-warning">{{ req.get_status_display }}</span>
|
||
<form hx-post="/hr-requests/{{ req.pk }}/cancel/" hx-target="#main-content" hx-indicator="#loader" style="margin:0;">
|
||
{% csrf_token %}
|
||
<input type="hidden" name="return_to" value="profile">
|
||
<button type="submit" class="btn btn-ghost" style="font-size:0.625rem; padding:0.15rem 0.35rem;">{% trans "Отменить" %}</button>
|
||
</form>
|
||
{% elif req.status == 'approved' %}
|
||
<span class="badge badge-success">{{ req.get_status_display }}</span>
|
||
{% elif req.status == 'rejected' %}
|
||
<span class="badge badge-danger">{{ req.get_status_display }}</span>
|
||
{% else %}
|
||
<span class="badge badge-muted">{{ req.get_status_display }}</span>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% empty %}
|
||
<div style="padding:1.25rem; text-align:center; color:var(--color-muted-foreground); font-size:0.8125rem;">{% trans "Заявок пока нет" %}</div>
|
||
{% endfor %}
|
||
</div>
|
||
<div>
|
||
<div style="padding:0.75rem 1.25rem; border-bottom:1px solid var(--color-border); font-size:0.8125rem; font-weight:500;">{% trans "Баланс отпусков" %} — {{ leave_balance_year }}</div>
|
||
<div style="padding:1rem 1.25rem; display:flex; flex-direction:column; gap:0.875rem;">
|
||
{% for row in leave_balance %}
|
||
<div>
|
||
<div style="display:flex; justify-content:space-between; margin-bottom:0.25rem; font-size:0.8125rem;">
|
||
<span>{{ row.label }}</span>
|
||
<span style="font-weight:600;">{{ row.used }}/{{ row.entitlement }} {% trans "дн." %}</span>
|
||
</div>
|
||
<div class="progress"><div class="progress-bar" style="width:{{ row.used_pct }}%;{% if row.key == 'sick' %} background:hsl(38 80% 45%);{% endif %}"></div></div>
|
||
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.2rem;">{% trans "Остаток" %}: {{ row.remaining }}{% if row.pending %} · {% trans "ожидает" %}: {{ row.pending }}{% endif %}</div>
|
||
</div>
|
||
{% endfor %}
|
||
{% if next_vacation_request %}
|
||
<div style="padding:0.75rem; background:var(--color-muted); border-radius:0.5rem; font-size:0.8125rem;">
|
||
<div style="font-weight:600; margin-bottom:0.25rem;">{% trans "Следующий отпуск" %}</div>
|
||
<div style="display:flex; justify-content:space-between; gap:0.5rem;">
|
||
<span style="color:var(--color-muted-foreground);">{{ next_vacation_request.summary }}</span>
|
||
<span class="badge badge-warning">{{ next_vacation_request.get_status_display }}</span>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|