Spaces:
Paused
Paused
| {% extends "base.html" %} | |
| {% block title %}Задачи{% endblock %} | |
| {% block page_title %}Задачи{% endblock %} | |
| {% block content %} | |
| <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;"> | |
| <h2 style="margin:0;font-size:15px;font-weight:600;color:#fff;">Задачи</h2> | |
| {% if current_user.role in ('admin', 'senior_expert') %} | |
| <a href="{{ url_for('admin.create_task') }}" class="btn-apple"> | |
| <i class="bi bi-plus-lg"></i> Новая задача | |
| </a> | |
| {% endif %} | |
| </div> | |
| {% macro task_table(tasks, show_assigner=False) %} | |
| <div class="d-card" style="border-radius:20px;background:rgba(6,11,40,0.6);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.05);overflow:hidden;"> | |
| <div class="d-card-body" style="padding: 0;"> | |
| {% if tasks %} | |
| <div class="table-responsive"> | |
| <table class="d-table-card"> | |
| <thead> | |
| <tr> | |
| <th style="padding-left: 16px;color:#A0A5B5;">Задача</th> | |
| {% if show_assigner %}<th style="color:#A0A5B5;">От кого</th>{% endif %} | |
| <th style="color:#A0A5B5;">{% if show_assigner %}Кому{% else %}Назначена{% endif %}</th> | |
| <th style="color:#A0A5B5;">Приоритет</th> | |
| <th style="color:#A0A5B5;">Статус</th> | |
| <th style="color:#A0A5B5;">Срок</th> | |
| <th style="text-align:right;padding-right:16px;color:#A0A5B5;">Действия</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| {% for t in tasks %} | |
| <tr> | |
| <td style="padding-left: 16px; font-weight: 500;"> | |
| {{ t.title }} | |
| {% if t.rework_comment %} | |
| <i class="bi bi-arrow-counterclockwise" style="color: #d97706; margin-left: 6px;" title="Отправлено на доработку"></i> | |
| {% endif %} | |
| </td> | |
| {% if show_assigner %}<td>{{ t.assigner.full_name if t.assigner else '—' }}</td>{% endif %} | |
| <td>{% if show_assigner %}{{ t.assignee.full_name }}{% else %}{{ t.assigner.full_name if t.assigner else '—' }}{% endif %}</td> | |
| <td> | |
| <span style="font-size:10px;font-weight:600;padding:1px 8px;border-radius:999px;{% if t.priority == 'high' %}background:rgba(220,38,38,0.1);color:#dc2626;{% elif t.priority == 'medium' %}background:rgba(217,119,6,0.1);color:#d97706;{% else %}background:rgba(37,99,235,0.1);color:#2563eb;{% endif %}"> | |
| {{ {'high': 'Высокий', 'medium': 'Средний', 'low': 'Низкий'}.get(t.priority, t.priority) }} | |
| </span> | |
| </td> | |
| <td> | |
| <span style="font-size:10px;font-weight:600;padding:1px 8px;border-radius:999px;{% if t.status == 'completed' %}background:rgba(22,163,74,0.1);color:#16a34a;{% elif t.status == 'in_progress' %}background:rgba(37,99,235,0.1);color:#2563eb;{% elif t.status == 'cancelled' %}background:rgba(100,116,139,0.1);color:#A0A5B5;{% else %}background:rgba(217,119,6,0.1);color:#d97706;{% endif %}"> | |
| {{ {'pending': 'Ожидает', 'in_progress': 'В работе', 'completed': 'Готово', 'cancelled': 'Отменено'}.get(t.status, t.status) }} | |
| </span> | |
| </td> | |
| <td>{{ t.due_date.strftime('%d.%m.%Y') if t.due_date else '—' }}</td> | |
| <td style="text-align: right; padding-right: 16px;"> | |
| <div style="display: inline-flex; gap: 4px; align-items: center;"> | |
| {% if t.assigned_to == current_user.id or current_user.role == 'admin' %} | |
| <a href="{{ url_for('admin.update_task_status', task_id=t.id, status='in_progress') }}" class="btn-apple-outline btn-apple-sm" title="В работе" style="color: #2563eb; border-color: #2563eb;">🔄</a> | |
| <a href="{{ url_for('admin.update_task_status', task_id=t.id, status='completed') }}" class="btn-apple-outline btn-apple-sm" title="Готово" style="color: #16a34a; border-color: #16a34a;">✓</a> | |
| {% endif %} | |
| {% if t.assigned_by == current_user.id or current_user.role == 'admin' %} | |
| <button type="button" class="btn-apple-outline btn-apple-sm rework-btn" title="На доработку" style="color: #d97706; border-color: #d97706;" data-task-id="{{ t.id }}" data-task-title="{{ t.title }}">↩</button> | |
| <a href="{{ url_for('admin.edit_task', task_id=t.id) }}" class="btn-apple-outline btn-apple-sm" title="Редактировать"><i class="bi bi-pencil"></i></a> | |
| {% endif %} | |
| {% if current_user.role == 'admin' %} | |
| <a href="{{ url_for('admin.delete_task', task_id=t.id) }}" class="btn-apple-outline btn-apple-sm" title="Удалить" style="color:#ef4444;border-color:#ef4444;" onclick="return confirm('Удалить задачу?')"><svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M2 4h12M5 4V2.5A1.5 1.5 0 016.5 1h3A1.5 1.5 0 0111 2.5V4M3 4v9.5A1.5 1.5 0 004.5 15h7a1.5 1.5 0 001.5-1.5V4"/></svg></a> | |
| {% endif %} | |
| <span style="font-size: 0.75rem; color: #999; max-width: 120px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="{{ t.description or '' }}"> | |
| {% if t.description %}<i class="bi bi-chat-dots" style="margin-left: 4px;"></i>{% endif %} | |
| </span> | |
| </div> | |
| </td> | |
| </tr> | |
| {% endfor %} | |
| </tbody> | |
| </table> | |
| </div> | |
| {% else %} | |
| <div style="text-align: center; padding: 40px 0;"> | |
| <i class="bi bi-clipboard-check" style="font-size:2.5rem;color:#A0A5B5;"></i> | |
| <p style="color:#A0A5B5;margin-top:8px;">Нет задач</p> | |
| </div> | |
| {% endif %} | |
| </div> | |
| </div> | |
| {% endmacro %} | |
| {% if current_user.role == 'admin' %} | |
| {{ task_table(tasks=assigned_tasks, show_assigner=False) }} | |
| {% else %} | |
| {% if assigned_tasks %} | |
| <h3 style="font-size:14px;font-weight:600;margin-bottom:12px;color:#fff;">Мои задачи</h3> | |
| {{ task_table(tasks=assigned_tasks, show_assigner=True) }} | |
| {% endif %} | |
| {% if created_tasks %} | |
| <h3 style="font-size:14px;font-weight:600;margin:24px 0 12px;color:#fff;">Я назначил</h3> | |
| {{ task_table(tasks=created_tasks, show_assigner=False) }} | |
| {% endif %} | |
| {% if not assigned_tasks and not created_tasks %} | |
| <div class="d-card" style="border-radius:20px;background:rgba(6,11,40,0.6);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.05);"> | |
| <div class="d-card-body" style="text-align:center;padding:40px 0;"> | |
| <i class="bi bi-clipboard-check" style="font-size:2.5rem;color:#A0A5B5;"></i> | |
| <p style="color:#A0A5B5;margin-top:8px;">Нет задач</p> | |
| </div> | |
| </div> | |
| {% endif %} | |
| {% endif %} | |
| <div id="reworkModal" class="modal-overlay" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.6);z-index:1000;align-items:center;justify-content:center;"> | |
| <div style="max-width:450px;width:90%;border-radius:20px;background:rgba(6,11,40,0.95);backdrop-filter:blur(20px);border:1px solid rgba(255,255,255,0.1);overflow:hidden;"> | |
| <div style="display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border-bottom:1px solid rgba(255,255,255,0.05);"> | |
| <h5 style="margin:0;font-size:15px;font-weight:600;color:#fff;">Отправить на доработку</h5> | |
| <button type="button" style="background:none;border:none;font-size:20px;color:#A0A5B5;cursor:pointer;" onclick="closeReworkModal()">×</button> | |
| </div> | |
| <form id="reworkForm" method="POST"> | |
| <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> | |
| <div style="padding:16px;"> | |
| <p style="margin:0 0 8px;font-size:13px;color:#A0A5B5;" id="reworkTaskTitle"></p> | |
| <textarea name="rework_comment" class="form-control form-control-sm" rows="3" placeholder="Что нужно исправить?" required style="background:rgba(6,11,40,0.6);border-color:rgba(255,255,255,0.1);color:#fff;border-radius:12px;"></textarea> | |
| </div> | |
| <div style="display:flex;gap:8px;justify-content:flex-end;padding:12px 16px;border-top:1px solid rgba(255,255,255,0.05);"> | |
| <button type="button" class="btn-apple-outline" onclick="closeReworkModal()" style="border-radius:12px;">Отмена</button> | |
| <button type="submit" class="btn-apple" style="background:#d97706;border-radius:12px;">Отправить</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| {% endblock %} | |
| {% block scripts %} | |
| <script> | |
| document.querySelectorAll('.rework-btn').forEach(btn => { | |
| btn.addEventListener('click', function() { | |
| const taskId = this.dataset.taskId; | |
| const taskTitle = this.dataset.taskTitle; | |
| document.getElementById('reworkTaskTitle').textContent = taskTitle; | |
| document.getElementById('reworkForm').action = '/admin/tasks/rework/' + taskId; | |
| document.getElementById('reworkModal').style.display = 'flex'; | |
| }); | |
| }); | |
| function closeReworkModal() { | |
| document.getElementById('reworkModal').style.display = 'none'; | |
| } | |
| </script> | |
| {% endblock %} | |