03019898b0
Добавлена офлайн/EndUser-подпись «ознакомлен и принял в работу» для документов отчётов и файловые вложения к задачам через Nextcloud. Co-authored-by: Cursor <cursoragent@cursor.com>
275 lines
19 KiB
HTML
275 lines
19 KiB
HTML
{% load i18n %}
|
||
<div class="page-content">
|
||
|
||
<div style="margin-bottom:1rem;">
|
||
<a href="/reports/" hx-get="/reports/" hx-target="#main-content" hx-push-url="/reports/" hx-indicator="#loader"
|
||
style="font-size:0.8125rem; color:var(--color-muted-foreground); text-decoration:none;">← {% trans "Все отчёты" %}</a>
|
||
</div>
|
||
|
||
{% if reports_message %}
|
||
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; background:color-mix(in srgb, var(--color-primary) 12%, transparent); font-size:0.875rem;">{{ reports_message }}</div>
|
||
{% endif %}
|
||
{% if reports_error %}
|
||
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; background:color-mix(in srgb, #dc2626 12%, transparent); font-size:0.875rem; color:#b91c1c;">{{ reports_error }}</div>
|
||
{% endif %}
|
||
|
||
{% with report=report %}
|
||
<div style="display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:space-between; gap:1rem; margin-bottom:1.25rem;">
|
||
<div>
|
||
<h1 style="font-size:1.25rem; font-weight:500; color:var(--color-foreground); margin:0;">{{ report.title }}</h1>
|
||
<p style="font-size:0.8125rem; color:var(--color-muted-foreground); margin:0.25rem 0 0;">
|
||
{% if show_live_report and report.period_from %}
|
||
{% trans "Период" %}: {{ report.period_from }} – {{ report.period_to }}
|
||
{% else %}
|
||
{% trans "Месяц" %}: {{ report.id }}
|
||
{% endif %}
|
||
{% if report_is_published %}
|
||
· <span style="color:var(--color-primary);">{% trans "Опубликован" %}</span>
|
||
{% elif can_publish_report %}
|
||
· <span style="color:var(--color-muted-foreground);">{% trans "Черновик — виден только руководителю" %}</span>
|
||
{% endif %}
|
||
</p>
|
||
{% if can_publish_report %}
|
||
<p style="font-size:0.75rem; color:var(--color-muted-foreground); margin:0.35rem 0 0; max-width:36rem;">
|
||
{% trans "Сформируйте Word, поправьте в редакторе, затем опубликуйте документ в «Документах отдела» — тогда отчёт увидит отдел." %}
|
||
</p>
|
||
{% endif %}
|
||
</div>
|
||
<div style="display:flex; flex-wrap:wrap; gap:0.5rem; align-items:center;">
|
||
<form method="get" action="/reports/it/monthly/"
|
||
hx-get="/reports/it/monthly/" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
|
||
style="display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap;">
|
||
<label for="report-month" style="font-size:0.8125rem; color:var(--color-muted-foreground);">{% trans "Месяц" %}</label>
|
||
<select name="month" id="report-month" class="input" onchange="this.form.requestSubmit()" style="min-width:9rem;">
|
||
{% for m in report.available_months %}
|
||
<option value="{{ m }}" {% if m == report.id %}selected{% endif %}>{{ m }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</form>
|
||
{% if can_publish_report %}
|
||
{% if report_is_published %}
|
||
<form method="post" action="/reports/it/monthly/{{ report.id }}/unpublish/" style="display:inline;">
|
||
{% csrf_token %}
|
||
<button type="submit" class="btn btn-secondary">{% trans "Снять с публикации" %}</button>
|
||
</form>
|
||
{% endif %}
|
||
{% if can_prepare_word %}
|
||
<form method="post" action="/reports/it/monthly/{{ report.id }}/publish/" style="display:inline;">
|
||
{% csrf_token %}
|
||
<button type="submit" class="btn btn-primary">{% trans "Сформировать Word" %}</button>
|
||
</form>
|
||
{% endif %}
|
||
{% endif %}
|
||
{% if show_live_report %}
|
||
<button type="button" class="btn btn-secondary"
|
||
onclick="itReportPreviewOpen('/reports/it/monthly/{{ report.id }}/preview/', '{{ report.title|escapejs }}')">
|
||
{% trans "Предпросмотр" %}
|
||
</button>
|
||
<a href="/reports/it/monthly/{{ report.id }}.pdf" class="btn btn-secondary">{% trans "Скачать PDF" %}</a>
|
||
<a href="/reports/it/monthly/{{ report.id }}.docx" class="btn btn-secondary">{% trans "Скачать Word" %}</a>
|
||
<a href="/reports/it/monthly/{{ report.id }}.md" class="btn btn-secondary" download>{% trans "Скачать Markdown" %}</a>
|
||
{% if can_manage_templates %}
|
||
<a href="/reports/templates/" hx-get="/reports/templates/" hx-target="#main-content" hx-push-url="/reports/templates/" hx-indicator="#loader"
|
||
class="btn btn-ghost" style="font-size:0.8125rem;">{% trans "Шаблон HTML-превью" %}</a>
|
||
{% endif %}
|
||
{% endif %}
|
||
{% if published_document %}
|
||
<a href="{% url 'report_document_download' published_document.pk %}" class="btn btn-primary">{% trans "Скачать опубликованный Word" %}</a>
|
||
<a href="{% url 'report_document_sign' published_document.pk %}"
|
||
hx-get="{% url 'report_document_sign' published_document.pk %}" hx-target="#main-content"
|
||
hx-push-url="{% url 'report_document_sign' published_document.pk %}" hx-indicator="#loader"
|
||
class="btn btn-secondary">{% trans "Подписать КЕП" %}</a>
|
||
{% if kep_signature %}
|
||
<a href="{% url 'report_document_signed_download' published_document.pk kep_signature.pk %}"
|
||
class="btn btn-ghost" style="font-size:0.8125rem;">{% trans "Подписанный PDF" %}</a>
|
||
{% endif %}
|
||
{% if show_live_report and onlyoffice_ready %}
|
||
<a href="/documents/edit/?report_doc={{ published_document.pk }}" class="btn btn-secondary">{% trans "Открыть Word" %}</a>
|
||
{% endif %}
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
{% if not show_live_report %}
|
||
<div style="background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; padding:1.25rem;">
|
||
{% if published_document %}
|
||
<p style="margin:0 0 0.75rem; font-size:0.9375rem;">{% trans "Опубликованный файл отчёта:" %} <strong>{{ published_document.title }}</strong></p>
|
||
<div style="display:flex; flex-wrap:wrap; gap:0.5rem; align-items:center;">
|
||
<a href="{% url 'report_document_download' published_document.pk %}" class="btn btn-primary">{% trans "Скачать Word" %}</a>
|
||
<a href="{% url 'report_document_sign' published_document.pk %}"
|
||
hx-get="{% url 'report_document_sign' published_document.pk %}" hx-target="#main-content"
|
||
hx-push-url="{% url 'report_document_sign' published_document.pk %}" hx-indicator="#loader"
|
||
class="btn btn-secondary">{% trans "Подписать КЕП" %}</a>
|
||
{% if kep_signature %}
|
||
<span class="badge badge-success">{% trans "Подписано КЕП" %}</span>
|
||
<a href="{% url 'report_document_signed_download' published_document.pk kep_signature.pk %}"
|
||
class="btn btn-ghost" style="font-size:0.8125rem;">{% trans "Подписанный PDF" %}</a>
|
||
{% endif %}
|
||
</div>
|
||
{% else %}
|
||
<p style="margin:0; color:var(--color-muted-foreground);">{% trans "Опубликованный Word-файл для этого месяца пока не найден." %}</p>
|
||
{% endif %}
|
||
</div>
|
||
{% else %}
|
||
|
||
<div style="display:grid; grid-template-columns:repeat(4, minmax(0,1fr)); gap:0.75rem; margin-bottom:1.25rem;">
|
||
<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;">{% trans "Всего работ" %}</div>
|
||
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ report.total_tasks }}</div>
|
||
</div>
|
||
<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;">{% trans "Сотрудников" %}</div>
|
||
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ report.people_active }}</div>
|
||
</div>
|
||
<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;">{% trans "Объектов" %}</div>
|
||
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ report.objects_count }}</div>
|
||
</div>
|
||
<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;">{% trans "Направлений" %}</div>
|
||
<div style="font-size:1.5rem; font-weight:500; color:var(--color-foreground);">{{ report.summary|length }}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display:grid; grid-template-columns:minmax(0,1.1fr) minmax(0,1fr); gap:1rem; margin-bottom:1.25rem;">
|
||
<div style="background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; padding:1rem 1.25rem;">
|
||
<h3 style="font-size:0.9375rem; font-weight:500; margin:0 0 0.75rem;">{% trans "Сводка по направлениям" %}</h3>
|
||
{% if report.summary %}
|
||
<ul style="list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:0.5rem;">
|
||
{% for row in report.summary %}
|
||
<li style="display:flex; justify-content:space-between; gap:1rem; font-size:0.875rem; border-bottom:1px solid var(--color-border); padding-bottom:0.5rem;">
|
||
<span>
|
||
<span style="color:var(--color-foreground);">{{ row.name }}</span>
|
||
{% if row.people %}<span style="color:var(--color-muted-foreground); font-size:0.75rem;"> — {{ row.people }}</span>{% endif %}
|
||
</span>
|
||
<strong style="color:var(--color-foreground);">{{ row.count }}</strong>
|
||
</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% else %}
|
||
<p style="color:var(--color-muted-foreground); font-size:0.875rem; margin:0;">{% trans "За выбранный месяц записей в журнале нет." %}</p>
|
||
{% endif %}
|
||
</div>
|
||
<div style="background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; padding:1rem 1.25rem;">
|
||
<h3 style="font-size:0.9375rem; font-weight:500; margin:0 0 0.75rem;">{% trans "Объекты" %}</h3>
|
||
{% if report.pharmacies %}
|
||
<p style="font-size:0.8125rem; margin:0 0 0.5rem;"><span style="color:var(--color-muted-foreground);">{% trans "Аптеки" %}:</span> {{ report.pharmacies|join:", " }}</p>
|
||
{% endif %}
|
||
{% if report.other_points %}
|
||
<p style="font-size:0.8125rem; margin:0 0 0.5rem;"><span style="color:var(--color-muted-foreground);">{% trans "Другие объекты" %}:</span> {{ report.other_points|join:", " }}</p>
|
||
{% endif %}
|
||
{% if not report.pharmacies and not report.other_points %}
|
||
<p style="color:var(--color-muted-foreground); font-size:0.875rem; margin:0;">{% trans "Объекты не указаны." %}</p>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
|
||
{% if report.conclusions %}
|
||
<div style="background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; padding:1rem 1.25rem; margin-bottom:1.25rem;">
|
||
<h3 style="font-size:0.9375rem; font-weight:500; margin:0 0 0.75rem;">{% trans "Основные выводы и рекомендации" %}</h3>
|
||
<div style="display:flex; flex-direction:column; gap:0.75rem;">
|
||
{% for item in report.conclusions %}
|
||
<div style="font-size:0.875rem; color:var(--color-foreground); line-height:1.45;">
|
||
<div>{{ item.text }}</div>
|
||
{% if item.bullets %}
|
||
<ul style="margin:0.375rem 0 0; padding-left:1.25rem; color:var(--color-muted-foreground); font-size:0.8125rem;">
|
||
{% for bullet in item.bullets %}
|
||
<li style="margin-bottom:0.2rem;">{{ bullet }}</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% endif %}
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
|
||
{% for emp in report.employees %}
|
||
{% if emp.tasks or emp.systems %}
|
||
<div style="background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; padding:1rem 1.25rem; margin-bottom:0.75rem;">
|
||
<div style="display:flex; justify-content:space-between; gap:1rem; align-items:baseline; margin-bottom:0.75rem;">
|
||
<div>
|
||
<h3 style="font-size:0.9375rem; font-weight:500; margin:0;">{{ emp.name }}</h3>
|
||
{% if emp.role %}<div style="font-size:0.75rem; color:var(--color-muted-foreground);">{{ emp.role }}</div>{% endif %}
|
||
</div>
|
||
<div style="font-size:0.75rem; color:var(--color-muted-foreground); white-space:nowrap;">
|
||
{{ emp.tasks_count }} {% trans "работ" %}{% if emp.systems_count %} · {{ emp.systems_count }} {% trans "систем" %}{% endif %}
|
||
</div>
|
||
</div>
|
||
{% if emp.systems %}
|
||
<div style="margin-bottom:0.75rem;">
|
||
{% for sys in emp.systems %}
|
||
<div style="font-size:0.8125rem; margin-bottom:0.375rem;">
|
||
<strong>{{ sys.name }}</strong>
|
||
<span style="color:var(--color-muted-foreground);"> — {{ sys.work }}</span>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
{% if emp.tasks %}
|
||
<div style="overflow-x:auto;">
|
||
<table style="width:100%; border-collapse:collapse; font-size:0.8125rem;">
|
||
<thead>
|
||
<tr style="border-bottom:1px solid var(--color-border);">
|
||
<th style="padding:0.5rem 0.75rem 0.5rem 0; text-align:left; color:var(--color-muted-foreground); font-weight:600; width:6.5rem;">{% trans "Дата" %}</th>
|
||
<th style="padding:0.5rem 0.75rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; width:4.5rem;">{% trans "Объект" %}</th>
|
||
<th style="padding:0.5rem 0; text-align:left; color:var(--color-muted-foreground); font-weight:600;">{% trans "Работы" %}</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for task in emp.tasks %}
|
||
<tr style="border-bottom:1px solid var(--color-border); vertical-align:top;">
|
||
<td style="padding:0.625rem 0.75rem 0.625rem 0; color:var(--color-muted-foreground); white-space:nowrap;">{{ task.date }}</td>
|
||
<td style="padding:0.625rem 0.75rem; color:var(--color-foreground); font-weight:500; white-space:nowrap;">{{ task.object|default:"—" }}</td>
|
||
<td style="padding:0.625rem 0; color:var(--color-foreground);">
|
||
{% if task.work_items|length > 1 %}
|
||
<ul style="margin:0; padding-left:1.1rem; display:flex; flex-direction:column; gap:0.2rem;">
|
||
{% for item in task.work_items %}
|
||
<li style="line-height:1.35;">{{ item }}</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% else %}
|
||
<span style="line-height:1.4;">{{ task.work }}</span>
|
||
{% endif %}
|
||
{% if task.ticket %} <span class="badge badge-muted">{{ task.ticket }}</span>{% endif %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
{% endif %}
|
||
{% empty %}
|
||
<p style="color:var(--color-muted-foreground);">{% trans "Нет данных для отчёта." %}</p>
|
||
{% endfor %}
|
||
|
||
<div id="it-report-preview-overlay" onclick="itReportPreviewClose()"
|
||
style="display:none; position:fixed; inset:0; background:rgba(15,23,42,0.55); z-index:1100;"></div>
|
||
<div id="it-report-preview-modal" role="dialog" aria-modal="true" aria-labelledby="it-report-preview-title"
|
||
onclick="itReportPreviewClose()"
|
||
style="display:none; position:fixed; inset:0; z-index:1101; padding:1.25rem; box-sizing:border-box; align-items:center; justify-content:center;">
|
||
<div style="width:min(920px, 96vw); height:min(90vh, 980px); background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 24px 64px rgba(0,0,0,0.28); display:flex; flex-direction:column; overflow:hidden;"
|
||
onclick="event.stopPropagation()">
|
||
<div style="display:flex; align-items:center; justify-content:space-between; gap:1rem; padding:0.75rem 1rem; border-bottom:1px solid var(--color-border); flex-shrink:0;">
|
||
<div>
|
||
<div id="it-report-preview-title" style="font-size:0.9375rem; font-weight:500; color:var(--color-foreground);">{% trans "Предпросмотр отчёта" %}</div>
|
||
<div id="it-report-preview-subtitle" style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.125rem;"></div>
|
||
</div>
|
||
<div style="display:flex; gap:0.5rem; align-items:center;">
|
||
<a id="it-report-preview-open-tab" href="#" target="_blank" rel="noopener" class="btn btn-ghost" style="font-size:0.8125rem;">{% trans "В новой вкладке" %}</a>
|
||
<button type="button" class="btn btn-ghost btn-icon" onclick="itReportPreviewClose()" aria-label="{% trans 'Закрыть' %}">✕</button>
|
||
</div>
|
||
</div>
|
||
<div style="flex:1; min-height:0; background:#e8edf4;">
|
||
<iframe id="it-report-preview-frame" title="{% trans 'Предпросмотр отчёта' %}"
|
||
style="width:100%; height:100%; border:0; background:#e8edf4;"></iframe>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
{% endwith %}
|
||
|
||
</div>
|