0da9c13192
Иерархия рамочных/дочерних договоров и платежей, интернет-биллинг, месячные IT-отчёты (импорт, DOCX/PDF, шаблоны выводов). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
174 lines
13 KiB
HTML
174 lines
13 KiB
HTML
{% load i18n %}
|
||
<div class="page-content" id="report-tpl-editor-root"
|
||
data-tpl-id="{{ tpl.pk }}"
|
||
data-readonly="{% if can_edit %}0{% else %}1{% endif %}"
|
||
data-mode="{{ editor_mode }}">
|
||
|
||
<div style="margin-bottom:1rem;">
|
||
<a href="/reports/templates/" hx-get="/reports/templates/" hx-target="#main-content" hx-push-url="/reports/templates/" hx-indicator="#loader"
|
||
style="font-size:0.8125rem; color:var(--color-muted-foreground); text-decoration:none;">← {% trans "К списку шаблонов" %}</a>
|
||
</div>
|
||
|
||
<div style="display:flex; align-items:flex-start; justify-content:space-between; gap:1rem; flex-wrap:wrap; margin-bottom:1rem;">
|
||
<div>
|
||
<h1 style="font-size:1.25rem; font-weight:500; margin:0;">{{ tpl.name }}</h1>
|
||
<div style="font-size:0.8125rem; color:var(--color-muted-foreground); margin-top:0.25rem;">
|
||
<code>{{ tpl.code }}</code>
|
||
{% if tpl.is_system %} · {% trans "системный" %}{% endif %}
|
||
{% if tpl.is_default %} · {% trans "по умолчанию" %}{% endif %}
|
||
</div>
|
||
</div>
|
||
<div style="display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap;">
|
||
<label for="tpl-preview-month" style="font-size:0.75rem; color:var(--color-muted-foreground);">{% trans "Данные месяца" %}</label>
|
||
<select id="tpl-preview-month" class="input" style="width:auto; min-width:8rem;">
|
||
{% for m in preview_months %}
|
||
<option value="{{ m }}" {% if m == preview_month %}selected{% endif %}>{{ m }}</option>
|
||
{% empty %}
|
||
<option value="">—</option>
|
||
{% endfor %}
|
||
</select>
|
||
<button type="button" id="report-tpl-preview-btn" class="btn btn-secondary" style="font-size:0.8125rem;">{% trans "Обновить превью" %}</button>
|
||
</div>
|
||
</div>
|
||
|
||
{% if message %}
|
||
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; border:1px solid hsl(152 40% 70%); background:color-mix(in srgb, var(--color-success) 12%, var(--color-card)); font-size:0.875rem;">{{ message }}</div>
|
||
{% endif %}
|
||
{% if error %}
|
||
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; border:1px solid color-mix(in srgb, var(--color-destructive) 40%, var(--color-border)); background:color-mix(in srgb, var(--color-destructive) 10%, var(--color-card)); font-size:0.875rem;">{{ error }}</div>
|
||
{% endif %}
|
||
|
||
{% if not can_edit %}
|
||
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; background:var(--color-muted); font-size:0.8125rem; color:var(--color-muted-foreground);">
|
||
{% trans "Системный шаблон только для чтения. Создайте копию, чтобы править под свои требования." %}
|
||
<form method="post" action="/reports/templates/{{ tpl.pk }}/copy/" style="display:inline; margin-left:0.5rem;">
|
||
{% csrf_token %}
|
||
<button type="submit" class="btn btn-primary" style="font-size:0.8125rem;">{% trans "Сделать копию" %}</button>
|
||
</form>
|
||
</div>
|
||
{% endif %}
|
||
|
||
<form id="report-tpl-form" method="post" action="/reports/templates/{{ tpl.pk }}/"
|
||
style="display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:1rem; align-items:stretch;">
|
||
{% csrf_token %}
|
||
<input type="hidden" name="engine" id="tpl-engine" value="{% if editor_mode == 'advanced' %}django_html{% else %}blocks_v1{% endif %}">
|
||
<textarea id="tpl-blocks" name="blocks" hidden>{{ blocks_json }}</textarea>
|
||
|
||
<div style="display:flex; flex-direction:column; gap:0.75rem; min-width:0;">
|
||
<div>
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Название" %}</label>
|
||
<input type="text" name="name" value="{{ tpl.name }}" class="input" style="width:100%;" {% if not can_edit %}readonly{% endif %}>
|
||
</div>
|
||
<div>
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Описание" %}</label>
|
||
<input type="text" name="description" value="{{ tpl.description }}" class="input" style="width:100%;" {% if not can_edit %}readonly{% endif %}>
|
||
</div>
|
||
<div style="display:flex; gap:1.5rem; flex-wrap:wrap; font-size:0.875rem;">
|
||
<label style="display:flex; align-items:center; gap:0.375rem;">
|
||
<input type="checkbox" name="is_default" {% if tpl.is_default %}checked{% endif %} {% if not can_edit %}disabled{% endif %}>
|
||
{% trans "По умолчанию" %}
|
||
</label>
|
||
<label style="display:flex; align-items:center; gap:0.375rem;">
|
||
<input type="checkbox" name="is_active" {% if tpl.is_active %}checked{% endif %} {% if not can_edit %}disabled{% endif %}>
|
||
{% trans "Активен" %}
|
||
</label>
|
||
</div>
|
||
|
||
<div style="display:flex; gap:0.25rem; border-bottom:1px solid var(--color-border); padding-bottom:0.25rem;">
|
||
<button type="button" class="btn btn-ghost tpl-mode-btn" data-mode="constructor"
|
||
style="font-size:0.8125rem; {% if editor_mode != 'advanced' %}font-weight:600; border-bottom:2px solid var(--color-primary); border-radius:0;{% endif %}">
|
||
{% trans "Конструктор" %}
|
||
</button>
|
||
<button type="button" class="btn btn-ghost tpl-mode-btn" data-mode="advanced"
|
||
style="font-size:0.8125rem; {% if editor_mode == 'advanced' %}font-weight:600; border-bottom:2px solid var(--color-primary); border-radius:0;{% endif %}">
|
||
{% trans "Расширенный HTML" %}
|
||
</button>
|
||
</div>
|
||
|
||
<div id="tpl-panel-constructor" {% if editor_mode == 'advanced' %}hidden{% endif %}>
|
||
<div style="margin-bottom:1rem;">
|
||
<div style="font-size:0.8125rem; font-weight:500; margin-bottom:0.5rem;">{% trans "Секции отчёта" %}</div>
|
||
<p style="font-size:0.75rem; color:var(--color-muted-foreground); margin:0 0 0.5rem;">
|
||
{% trans "Включайте нужные блоки и меняйте порядок стрелками." %}
|
||
</p>
|
||
<ul id="tpl-sections-list" style="list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:0.375rem;">
|
||
{% for sec in section_rows %}
|
||
<li class="tpl-section-row" data-section-id="{{ sec.id }}"
|
||
style="display:flex; align-items:center; gap:0.5rem; padding:0.5rem 0.625rem; border:1px solid var(--color-border); border-radius:var(--radius); background:var(--color-card); {% if not sec.enabled %}opacity:0.55;{% endif %}">
|
||
<label style="display:flex; align-items:center; gap:0.5rem; flex:1; min-width:0; cursor:pointer; font-size:0.875rem;">
|
||
<input type="checkbox" class="tpl-section-on" {% if sec.enabled %}checked{% endif %} {% if not can_edit %}disabled{% endif %}>
|
||
<span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">{{ sec.title }}</span>
|
||
</label>
|
||
<button type="button" class="btn btn-ghost tpl-sec-up" title="{% trans 'Выше' %}"
|
||
style="padding:0.25rem 0.4rem; font-size:0.75rem;" {% if not can_edit %}disabled{% endif %}>↑</button>
|
||
<button type="button" class="btn btn-ghost tpl-sec-down" title="{% trans 'Ниже' %}"
|
||
style="padding:0.25rem 0.4rem; font-size:0.75rem;" {% if not can_edit %}disabled{% endif %}>↓</button>
|
||
</li>
|
||
{% endfor %}
|
||
</ul>
|
||
</div>
|
||
|
||
<div>
|
||
<div style="font-size:0.8125rem; font-weight:500; margin-bottom:0.5rem;">{% trans "Подписи и заголовки" %}</div>
|
||
<div style="display:grid; gap:0.5rem;">
|
||
{% for field in label_fields %}
|
||
<div>
|
||
<label for="tpl-label-{{ field.key }}" style="display:block; font-size:0.75rem; color:var(--color-muted-foreground); margin-bottom:0.2rem;">{{ field.title }}</label>
|
||
<input type="text" id="tpl-label-{{ field.key }}" class="input tpl-label-input"
|
||
data-label-key="{{ field.key }}" value="{{ field.value }}"
|
||
style="width:100%; font-size:0.8125rem;" {% if not can_edit %}readonly{% endif %}>
|
||
</div>
|
||
{% endfor %}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="tpl-panel-advanced" {% if editor_mode != 'advanced' %}hidden{% endif %}>
|
||
<p style="font-size:0.75rem; color:var(--color-muted-foreground); margin:0 0 0.75rem;">
|
||
{% trans "Свободный Django HTML. При сохранении в этом режиме конструктор секций не используется для рендера." %}
|
||
</p>
|
||
<div style="margin-bottom:0.75rem;">
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "HTML (превью отчёта)" %}</label>
|
||
<div id="tpl-body-html-ace" style="height:18rem; border:1px solid var(--color-border); border-radius:var(--radius); overflow:hidden;"></div>
|
||
<textarea id="tpl-body-html" name="body_html" rows="10" class="input" style="width:100%; font-family:ui-monospace, monospace; font-size:0.75rem;">{% if not can_edit %}readonly{% endif %}>{{ tpl.body_html }}</textarea>
|
||
</div>
|
||
<div style="margin-bottom:0.75rem;">
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Markdown (.md)" %}</label>
|
||
<div id="tpl-body-md-ace" style="height:10rem; border:1px solid var(--color-border); border-radius:var(--radius); overflow:hidden;"></div>
|
||
<textarea id="tpl-body-md" name="body_md" rows="6" class="input" style="width:100%; font-family:ui-monospace, monospace; font-size:0.75rem;">{% if not can_edit %}readonly{% endif %}>{{ tpl.body_md }}</textarea>
|
||
</div>
|
||
<div>
|
||
<label style="display:block; font-size:0.8125rem; font-weight:500; margin-bottom:0.375rem;">{% trans "Blocks JSON" %}</label>
|
||
<div id="tpl-blocks-ace" style="height:8rem; border:1px solid var(--color-border); border-radius:var(--radius); overflow:hidden;"></div>
|
||
<textarea id="tpl-blocks-adv" rows="6" class="input" style="width:100%; font-family:ui-monospace, monospace; font-size:0.75rem;" hidden></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
{% if can_edit %}
|
||
<div style="display:flex; gap:0.5rem; flex-wrap:wrap;">
|
||
<button type="submit" class="btn btn-primary">{% trans "Сохранить" %}</button>
|
||
<a href="/reports/it/monthly/" class="btn btn-ghost"
|
||
hx-get="/reports/it/monthly/" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader">
|
||
{% trans "К отчёту" %}
|
||
</a>
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
|
||
<div style="min-width:0; display:flex; flex-direction:column; min-height:36rem; background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; overflow:hidden;">
|
||
<div style="padding:0.5rem 0.75rem; border-bottom:1px solid var(--color-border); font-size:0.8125rem; color:var(--color-muted-foreground); display:flex; justify-content:space-between;">
|
||
<span id="report-tpl-preview-status">{% trans "Предпросмотр" %}</span>
|
||
</div>
|
||
<iframe id="report-tpl-preview-frame" title="{% trans 'Предпросмотр шаблона' %}"
|
||
style="flex:1; width:100%; border:0; background:#e8edf4;"></iframe>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<style>
|
||
@media (max-width: 960px) {
|
||
#report-tpl-form { grid-template-columns: 1fr !important; }
|
||
#report-tpl-form > div:last-child { min-height: 24rem; }
|
||
}
|
||
</style>
|