Files
ACORE/templates/pages/task-detail.html
T
lokses 03019898b0 reports: КЕП-подпись PDF отчётов; задачи: загрузка вложений.
Добавлена офлайн/EndUser-подпись «ознакомлен и принял в работу» для документов отчётов и файловые вложения к задачам через Nextcloud.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 21:13:28 +03:00

229 lines
17 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 %}
<div class="page-content">
<!-- Назад -->
<div style="margin-bottom:1.25rem;">
<a class="btn btn-ghost" style="padding:0.375rem 0.5rem; font-size:0.8125rem; gap:0.375rem; color:var(--color-muted-foreground); cursor:pointer; text-decoration:none;"
href="/tasks/" hx-get="/tasks/" hx-target="#main-content" hx-push-url="/tasks/" hx-indicator="#loader">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m15 18-6-6 6-6"/></svg>
{% trans "Задачи" %}
</a>
</div>
<!-- Заголовок задачі -->
<div style="display:flex; align-items:flex-start; justify-content:space-between; gap:1rem; margin-bottom:1.5rem;">
<div style="flex:1;">
<div style="display:flex; align-items:center; gap:0.625rem; margin-bottom:0.5rem; flex-wrap:wrap;">
{% if task.status == 'done' %}
<span class="badge badge-success" style="gap:0.25rem;">✓ {% trans "Выполнено" %}</span>
{% elif task.status == 'in_progress' %}
<span class="badge badge-success" style="gap:0.25rem;"><span style="width:6px; height:6px; border-radius:50%; background:hsl(152 55% 45%);"></span>{% trans "В работе" %}</span>
{% elif task.status == 'cancelled' %}
<span class="badge badge-muted">{% trans "Отменено" %}</span>
{% else %}
<span class="badge badge-warning" style="gap:0.25rem;"><span style="width:6px; height:6px; border-radius:50%; background:hsl(38 92% 50%);"></span>{% trans "Ожидает" %}</span>
{% endif %}
<span class="badge {{ task.priority_badge }}">{{ task.get_priority_display }}</span>
{% if task.due_date %}
<span style="font-size:0.75rem; color:{% if task.is_overdue %}var(--color-destructive); font-weight:600;{% else %}var(--color-muted-foreground);{% endif %}">
{% trans "срок:" %} {{ task.due_date|date:"d.m.Y" }}{% if task.is_overdue %} — {% trans "просрочено" %}{% endif %}
</span>
{% endif %}
</div>
<h1 style="font-size:1.375rem; font-weight:600; color:var(--color-foreground); line-height:1.3;">{{ task.title }}</h1>
</div>
<div style="display:flex; gap:0.5rem; flex-shrink:0;">
{% if can_edit %}
<a href="/tasks/{{ task.pk }}/edit/" hx-get="/tasks/{{ task.pk }}/edit/" hx-target="#main-content" hx-push-url="/tasks/{{ task.pk }}/edit/" hx-indicator="#loader"
class="btn btn-secondary" style="font-size:0.8125rem; text-decoration:none;">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
{% trans "Редактировать" %}
</a>
{% endif %}
{% if can_delete %}
<form hx-post="/tasks/{{ task.pk }}/delete/" hx-target="#main-content" hx-push-url="/tasks/" hx-indicator="#loader"
hx-confirm="{% trans 'Удалить задачу' %} «{{ task.title }}»?" style="margin:0;">
{% csrf_token %}
<button type="submit" class="btn btn-ghost" style="font-size:0.8125rem; color:var(--color-destructive);">{% trans "Удалить" %}</button>
</form>
{% endif %}
</div>
</div>
<!-- Двоколонковий лейаут -->
<div style="display:grid; grid-template-columns:1fr 17rem; gap:1.25rem; align-items:start;">
<!-- Ліва колонка -->
<div style="display:flex; flex-direction:column; gap:1rem;">
<!-- Опис -->
<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; color:var(--color-foreground); margin-bottom:0.75rem;">{% trans "Описание" %}</h3>
{% if task.description %}
<div style="font-size:0.875rem; color:var(--color-muted-foreground); line-height:1.6; white-space:pre-line;">{{ task.description }}</div>
{% else %}
<div style="font-size:0.875rem; color:var(--color-muted-foreground); opacity:0.6;">{% trans "Описание не добавлено" %}</div>
{% endif %}
</div>
<!-- Чек-лист -->
{% if checklist %}
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.25rem;">
<div style="display:flex; align-items:center; gap:0.5rem; margin-bottom:0.75rem;">
<h3 style="font-size:0.875rem; font-weight:600; color:var(--color-foreground);">{% trans "Чек-лист" %}</h3>
<span style="font-size:0.6875rem; background:var(--color-muted); color:var(--color-muted-foreground); border-radius:999px; padding:0.0625rem 0.5rem; font-weight:500;">{{ task.checklist_done }}/{{ task.checklist_total }}</span>
</div>
<div style="display:flex; flex-direction:column; gap:0.125rem;">
{% for item in checklist %}
<label style="display:flex; align-items:center; gap:0.625rem; padding:0.4375rem 0.5rem; border-radius:0.5rem; font-size:0.875rem; {% if is_participant %}cursor:pointer;{% endif %} {% if item.is_done %}color:var(--color-muted-foreground);{% else %}color:var(--color-foreground);{% endif %}"
{% if is_participant %}class="tr-hover"{% endif %}>
<input type="checkbox" {% if item.is_done %}checked{% endif %} {% if not is_participant %}disabled{% endif %}
{% if is_participant %}hx-post="/tasks/{{ task.pk }}/" hx-target="#main-content" hx-indicator="#loader"
hx-vals='{"action": "checklist_toggle", "item_id": "{{ item.pk }}"}'{% endif %}
style="width:1rem; height:1rem; flex-shrink:0;">
<span style="{% if item.is_done %}text-decoration:line-through;{% endif %}">{{ item.label }}</span>
{% if item.is_done and item.done_by %}
<span style="margin-left:auto; font-size:0.6875rem; color:var(--color-muted-foreground); white-space:nowrap;">{{ item.done_by.short_name }} · {{ item.done_at|date:"d.m H:i" }}</span>
{% endif %}
</label>
{% endfor %}
</div>
</div>
{% endif %}
<!-- Вложения -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1.25rem;">
<div style="display:flex; align-items:center; gap:0.5rem; margin-bottom:0.75rem;">
<h3 style="font-size:0.875rem; font-weight:600; color:var(--color-foreground);">{% trans "Вложения" %}</h3>
<span style="font-size:0.6875rem; background:var(--color-muted); color:var(--color-muted-foreground); border-radius:999px; padding:0.0625rem 0.5rem; font-weight:500;">{{ attachments|length }}</span>
</div>
<div id="task-attachments-slot">
{% include "partials/task-attachments.html" %}
</div>
</div>
<!-- Коментарі -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); overflow:hidden;">
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border); display:flex; align-items:center; gap:0.5rem;">
<h3 style="font-size:0.875rem; font-weight:600; color:var(--color-foreground);">{% trans "Комментарии" %}</h3>
<span style="font-size:0.6875rem; background:var(--color-muted); color:var(--color-muted-foreground); border-radius:999px; padding:0.0625rem 0.5rem; font-weight:500;">{{ comments|length }}</span>
</div>
{% for comment in comments %}
<div style="padding:1rem 1.25rem; border-bottom:1px solid var(--color-border);">
<div style="display:flex; gap:0.75rem;">
<div style="width:2rem; height:2rem; border-radius:50%; background:hsl(174 55% 42% / 0.15); color:hsl(174 55% 35%); display:flex; align-items:center; justify-content:center; font-size:0.6875rem; font-weight:600; flex-shrink:0;">{{ comment.author|initials }}</div>
<div style="flex:1; min-width:0;">
<div style="display:flex; align-items:baseline; gap:0.5rem; margin-bottom:0.375rem;">
<span style="font-size:0.8125rem; font-weight:600; color:var(--color-foreground);">{{ comment.author.get_full_name|default:"—" }}</span>
<span style="font-size:0.75rem; color:var(--color-muted-foreground);">{{ comment.created_at|date:"d.m.Y, H:i" }}</span>
</div>
<p style="font-size:0.875rem; color:var(--color-muted-foreground); line-height:1.5; white-space:pre-line;">{{ comment.text }}</p>
</div>
</div>
</div>
{% empty %}
<div style="padding:1.25rem; text-align:center; color:var(--color-muted-foreground); font-size:0.8125rem;">{% trans "Комментариев пока нет" %}</div>
{% endfor %}
<!-- Форма коментаря -->
<form hx-post="/tasks/{{ task.pk }}/" hx-target="#main-content" hx-indicator="#loader"
style="padding:1rem 1.25rem; border-top:1px solid var(--color-border); display:flex; gap:0.75rem; align-items:flex-start; margin:0;">
{% csrf_token %}
<input type="hidden" name="action" value="comment">
<div style="width:2rem; height:2rem; border-radius:50%; background:var(--color-accent); color:var(--color-accent-foreground); display:flex; align-items:center; justify-content:center; font-size:0.625rem; font-weight:700; flex-shrink:0;">{{ request.user|initials }}</div>
<textarea name="text" required placeholder="{% trans 'Написать комментарий...' %}"
style="flex:1; min-height:2.5rem; resize:vertical; background:var(--color-muted); border:1px solid var(--color-border); border-radius:var(--radius); padding:0.5rem 0.75rem; font-size:0.875rem; color:var(--color-foreground); font-family:var(--font-sans); outline:none; box-sizing:border-box;"></textarea>
<button type="submit" class="btn btn-primary" style="flex-shrink:0;">{% trans "Отправить" %}</button>
</form>
</div>
</div>
<!-- Права колонка -->
<div style="display:flex; flex-direction:column; gap:1rem;">
{% if is_participant and task.status != 'cancelled' %}
<!-- Дії -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1rem 1.25rem; display:flex; flex-direction:column; gap:0.5rem;">
<h3 style="font-size:0.8125rem; font-weight:600; color:var(--color-foreground); margin-bottom:0.25rem;">{% trans "Действия" %}</h3>
{% if task.status == 'pending' %}
<form hx-post="/tasks/{{ task.pk }}/" hx-target="#main-content" hx-indicator="#loader" style="margin:0;">
{% csrf_token %}
<input type="hidden" name="action" value="status"><input type="hidden" name="status" value="in_progress">
<button type="submit" class="btn btn-primary" style="width:100%; font-size:0.8125rem;">{% trans "Взять в работу" %}</button>
</form>
{% endif %}
{% if task.status != 'done' %}
<form hx-post="/tasks/{{ task.pk }}/" hx-target="#main-content" hx-indicator="#loader" style="margin:0;">
{% csrf_token %}
<input type="hidden" name="action" value="status"><input type="hidden" name="status" value="done">
<button type="submit" class="btn btn-secondary" style="width:100%; font-size:0.8125rem;">✓ Позначити виконаною</button>
</form>
{% else %}
<form hx-post="/tasks/{{ task.pk }}/" hx-target="#main-content" hx-indicator="#loader" style="margin:0;">
{% csrf_token %}
<input type="hidden" name="action" value="status"><input type="hidden" name="status" value="pending">
<button type="submit" class="btn btn-secondary" style="width:100%; font-size:0.8125rem;">{% trans "Вернуть в работу" %}</button>
</form>
{% endif %}
{% if can_edit and task.status != 'done' %}
<form hx-post="/tasks/{{ task.pk }}/" hx-target="#main-content" hx-indicator="#loader" style="margin:0;">
{% csrf_token %}
<input type="hidden" name="action" value="status"><input type="hidden" name="status" value="cancelled">
<button type="submit" class="btn btn-ghost" style="width:100%; font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "Отменить задачу" %}</button>
</form>
{% endif %}
</div>
{% endif %}
<!-- Учасники -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1rem 1.25rem;">
<h3 style="font-size:0.8125rem; font-weight:600; color:var(--color-foreground); margin-bottom:0.75rem;">{% trans "Участники" %}</h3>
<div style="display:flex; flex-direction:column; gap:0.875rem;">
{% for role_label, role_people in role_groups %}
{% if role_people %}
<div>
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:0.5rem;">{{ role_label }}</div>
<div style="display:flex; flex-direction:column; gap:0.5rem;">
{% for emp in role_people %}
<div style="display:flex; align-items:center; gap:0.5rem;">
<div style="width:1.75rem; height:1.75rem; border-radius:50%; background:color-mix(in srgb, var(--color-primary) 10%, transparent); color:var(--color-primary); display:flex; align-items:center; justify-content:center; font-size:0.625rem; font-weight:600; flex-shrink:0;">{{ emp|initials }}</div>
<div>
<div style="font-size:0.8125rem; color:var(--color-foreground);">{{ emp.get_full_name }}</div>
{% if emp.post %}<div style="font-size:0.6875rem; color:var(--color-muted-foreground);">{{ emp.post.name }}</div>{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
{% if not task.responsible.all and not task.co_executors.all and not task.observers.all %}
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); opacity:0.6;">{% trans "Не назначено" %}</div>
{% endif %}
</div>
</div>
<!-- Інфо -->
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); padding:1rem 1.25rem; display:flex; flex-direction:column; gap:0.625rem;">
<div>
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:0.125rem;">{% trans "Автор" %}</div>
<div style="font-size:0.8125rem; color:var(--color-foreground);">{{ task.creator.get_full_name|default:"—" }}</div>
</div>
<div>
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:0.125rem;">{% trans "Создано" %}</div>
<div style="font-size:0.8125rem; color:var(--color-foreground);">{{ task.created_at|date:"d.m.Y H:i" }}</div>
</div>
{% if task.completed_at %}
<div>
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.04em; margin-bottom:0.125rem;">{% trans "Выполнено" %}</div>
<div style="font-size:0.8125rem; color:var(--color-foreground);">{{ task.completed_at|date:"d.m.Y H:i" }}</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>