Files
ACORE/templates/pages/employee-profile.html
T
lokses 3359a8db13 employees: HR-заявки, приглашения на пароль, профиль и 2FA
Модель/сервисы HR-заявок с заменами, приглашения на установку пароля
(инвайты), обновлённая страница профиля сотрудника и правки 2FA.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-09 18:03:32 +03:00

191 lines
17 KiB
HTML

{% load common_tags %}
{% load i18n %}
<div class="page-content" data-profile-active-tab="{{ profile_active_tab|default:'overview' }}">
{% with tab=profile_active_tab|default:'overview' %}
{% if saved %}
<div style="margin-bottom:1rem; padding:0.875rem 1rem; border-radius:0.75rem; border:1px solid hsl(152 40% 70%); background:hsl(152 45% 96%); color:var(--color-foreground); font-size:0.875rem;">
{% trans "Изменения сохранены" %}
</div>
{% endif %}
{% if errors %}
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; background:hsl(0 70% 96%); border:1px solid hsl(0 70% 85%); color:hsl(0 55% 35%); font-size:0.8125rem;">
{% for err in errors %}<div>{{ err }}</div>{% endfor %}
</div>
{% endif %}
{% if hr_request_created %}
<div style="margin-bottom:1rem; padding:0.875rem 1rem; border-radius:0.75rem; border:1px solid hsl(152 40% 70%); background:hsl(152 45% 96%); color:var(--color-foreground); font-size:0.875rem;">
{% trans "Заявку подано" %}: <strong>{{ hr_request_created.summary }}</strong>
</div>
{% endif %}
{% if hr_request_errors %}
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; background:hsl(0 70% 96%); border:1px solid hsl(0 70% 85%); color:hsl(0 55% 35%); font-size:0.8125rem;">
<div style="font-weight:600; margin-bottom:0.35rem;">{% trans "Не удалось подать заявку" %}</div>
{% for err in hr_request_errors %}<div>{{ err }}</div>{% endfor %}
</div>
{% endif %}
<div style="margin-bottom:1rem;">
{% if is_own_profile %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "Мой профиль" %}</div>
{% else %}
<a href="/hr-portal/" hx-get="/hr-portal/" hx-target="#main-content" hx-push-url="/hr-portal/" hx-indicator="#loader"
style="display:inline-flex; align-items:center; gap:0.375rem; font-size:0.8125rem; color:var(--color-muted-foreground); text-decoration:none;">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m12 19-7-7 7-7"/><path d="M19 12H5"/></svg>
{% trans "К списку сотрудников" %}
</a>
{% endif %}
</div>
<div class="emp-profile-layout" style="display:grid; grid-template-columns:minmax(13rem, 16rem) minmax(0, 1fr); gap:1.25rem; align-items:start;">
{% include "partials/employee-profile-aside.html" %}
<div style="min-width:0;">
<!-- Вкладки -->
<div style="display:flex; gap:0.25rem; background:var(--color-muted); border-radius:var(--radius); padding:0.25rem; width:fit-content; margin-bottom:1rem; flex-wrap:wrap; max-width:100%;">
<button type="button" class="emp-profile-tab-btn{% if tab == 'overview' %} emp-profile-tab-active{% endif %}" data-tab="overview" onclick="empProfileTabSwitch('overview')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer;{% if tab == 'overview' %} 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 is_own_profile or can_view_pii %}
<button type="button" class="emp-profile-tab-btn{% if tab == 'contacts' %} emp-profile-tab-active{% endif %}" data-tab="contacts" onclick="empProfileTabSwitch('contacts')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer;{% if tab == 'contacts' %} 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>
{% endif %}
<button type="button" class="emp-profile-tab-btn{% if tab == 'work' %} emp-profile-tab-active{% endif %}" data-tab="work" onclick="empProfileTabSwitch('work')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer;{% if tab == 'work' %} 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 is_own_profile %}
<button type="button" class="emp-profile-tab-btn{% if tab == 'settings' %} emp-profile-tab-active{% endif %}" data-tab="settings" onclick="empProfileTabSwitch('settings')"
style="padding:0.375rem 1rem; font-size:0.8125rem; font-weight:500; border:none; border-radius:calc(var(--radius) - 2px); cursor:pointer;{% if tab == 'settings' %} 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>
{% endif %}
</div>
<!-- Панель: Общая информация -->
<div id="emp-profile-panel-overview" class="emp-profile-panel"{% if tab != 'overview' %} style="display:none;"{% endif %}>
{% include "partials/employee-profile-overview.html" %}
</div>
<!-- Панель: Контакты -->
{% if is_own_profile or can_view_pii %}
<div id="emp-profile-panel-contacts" class="emp-profile-panel"{% if tab != 'contacts' %} style="display:none;"{% endif %}>
{% if is_own_profile %}
<form hx-post="/employees/{{ employee.pk }}/" hx-target="#main-content" hx-indicator="#loader" novalidate
style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.5rem;">
{% csrf_token %}
<input type="hidden" name="profile_tab" value="contacts">
<h3 style="font-weight:600; font-size:0.9375rem; margin-bottom:1.25rem;">{% trans "Контактные данные" %}</h3>
<div style="display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:1rem; margin-bottom:1.5rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Рабочий телефон" %}</label>
<input type="text" name="phone" value="{{ employee.phone }}" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Личный телефон" %}</label>
<input type="text" name="personal_phone" value="{{ employee.personal_phone }}" class="input" style="width:100%;">
</div>
<div style="grid-column:1 / -1;">
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Личный email" %}</label>
<input type="email" name="personal_email" value="{{ employee.personal_email }}" class="input" style="width:100%; max-width:24rem;">
</div>
</div>
<h3 style="font-weight:600; font-size:0.9375rem; margin-bottom:1.25rem;">{% trans "Контакт для экстренных случаев" %}</h3>
<div style="display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:1rem; margin-bottom:1.5rem;">
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Имя" %}</label>
<input type="text" name="emergency_contact_name" value="{{ employee.emergency_contact_name }}" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Телефон" %}</label>
<input type="text" name="emergency_contact_phone" value="{{ employee.emergency_contact_phone }}" class="input" style="width:100%;">
</div>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Степень родства" %}</label>
<input type="text" name="emergency_contact_relation" value="{{ employee.emergency_contact_relation }}" class="input" style="width:100%;">
</div>
</div>
<button type="submit" class="btn btn-primary">{% trans "Сохранить" %}</button>
</form>
{% else %}
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.25rem; max-width:48rem;">
<h3 style="font-size:0.875rem; font-weight:600; margin-bottom:0.875rem;">{% trans "Контакты" %}</h3>
<div style="display:grid; grid-template-columns:1fr 1fr; gap:0.875rem;">
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Рабочий email" %}</div><div>{{ employee.email|default:"—" }}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Рабочий телефон" %}</div><div>{{ employee.phone|default:"—" }}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Внутренний номер" %}</div><div>{{ employee.internal_number|default:"—" }}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Личный телефон" %}</div><div>{{ employee.personal_phone|default:"—" }}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Личный email" %}</div><div>{{ employee.personal_email|default:"—" }}</div></div>
</div>
{% if employee.emergency_contact_name %}
<div style="margin-top:1rem; padding-top:1rem; border-top:1px solid var(--color-border);">
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.375rem;">{% trans "Экстренный контакт" %}</div>
<div>{{ employee.emergency_contact_name }}{% if employee.emergency_contact_relation %} ({{ employee.emergency_contact_relation }}){% endif %}</div>
{% if employee.emergency_contact_phone %}<div style="font-size:0.8125rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ employee.emergency_contact_phone }}</div>{% endif %}
</div>
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
<!-- Панель: Работа -->
<div id="emp-profile-panel-work" class="emp-profile-panel"{% if tab != 'work' %} style="display:none;"{% endif %}>
<div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(280px, 1fr)); gap:1rem; align-items:start;">
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.25rem;">
<h3 style="font-size:0.875rem; font-weight:600; margin-bottom:0.875rem;">{% trans "Работа" %}</h3>
<div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(10rem, 1fr)); gap:0.875rem;">
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Организация" %}</div><div>{{ employee.user_organization.name|default:"—" }}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Отдел" %}</div><div>{{ employee.department.name|default:"—" }}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Должность" %}</div><div>{% if employee.post %}{{ employee.post.name }}{% else %}—{% endif %}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Внутренний номер" %}</div><div>{{ employee.internal_number|default:"—" }}</div></div>
{% if can_view_pii %}
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Дата приёма" %}</div><div>{{ employee.hire_date|date:"d.m.Y"|default:"—" }}{% if employee.hire_date %} <span style="color:var(--color-muted-foreground);">({{ employee.work_experience }} {% trans "л." %})</span>{% endif %}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Дата увольнения" %}</div><div>{{ employee.termination_date|date:"d.m.Y"|default:"—" }}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "Дата рождения" %}</div><div>{{ employee.birth_date|date:"d.m.Y"|default:"—" }}{% if employee.age %} ({{ employee.age }}){% endif %}</div></div>
<div><div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-bottom:0.125rem;">{% trans "ИНН" %}</div><div>{{ employee.inn_code|default:"—" }}</div></div>
{% endif %}
</div>
</div>
{% if can_view_pii %}
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.25rem;">
<h3 style="font-size:0.875rem; font-weight:600; margin-bottom:0.875rem;">{% trans "Интеграции" %}</h3>
<div style="display:flex; flex-direction:column; gap:0.625rem;">
<div style="display:flex; justify-content:space-between;"><span style="font-size:0.8125rem; color:var(--color-muted-foreground);">Mattermost</span>
{% if employee.mattermost_sync_status == 'synced' %}<span class="badge badge-success">OK</span>{% elif employee.mattermost_sync_status == 'error' %}<span class="badge badge-danger">{% trans "Ошибка" %}</span>{% else %}<span class="badge badge-muted">—</span>{% endif %}
</div>
<div style="display:flex; justify-content:space-between;"><span style="font-size:0.8125rem; color:var(--color-muted-foreground);">Active Directory</span>
{% if employee.ad_sync_status == 'synced' %}<span class="badge badge-success">OK</span>{% elif employee.ad_sync_status == 'error' %}<span class="badge badge-danger">{% trans "Ошибка" %}</span>{% else %}<span class="badge badge-muted">—</span>{% endif %}
</div>
</div>
</div>
{% endif %}
</div>
</div>
<!-- Панель: Настройки (только свой профиль) -->
{% if is_own_profile %}
<div id="emp-profile-panel-settings" class="emp-profile-panel"{% if tab != 'settings' %} style="display:none;"{% endif %}>
<div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(300px, 1fr)); gap:1rem; align-items:start;">
<form hx-post="/employees/{{ employee.pk }}/" hx-target="#main-content" hx-indicator="#loader"
style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.5rem;">
{% csrf_token %}
<input type="hidden" name="profile_tab" value="settings">
<h3 style="font-weight:600; font-size:0.9375rem; margin-bottom:1.25rem;">{% trans "Интерфейс" %}</h3>
<div>
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Записей в таблицах по умолчанию" %}</label>
<select name="default_page_size" class="input" style="width:auto; max-width:12rem;">
{% for size in page_size_choices %}
<option value="{{ size }}" {% if size == employee.default_page_size %}selected{% endif %}>{{ size }}</option>
{% endfor %}
</select>
<p style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.375rem;">{% trans "Применяется ко всем таблицам портала, если размер не выбран вручную." %}</p>
</div>
<button type="submit" class="btn btn-primary" style="margin-top:1.25rem;">{% trans "Сохранить" %}</button>
</form>
{% include "partials/employee-profile-2fa.html" %}
</div>
</div>
{% endif %}
</div>
</div>
{% endwith %}
</div>