Add initial implementations for forms and organization apps with serializers, factories, and admin configurations
Some checks failed
CI/CD Pipeline / Run Tests (push) Failing after 45s
CI/CD Pipeline / Code Quality Checks (push) Failing after 48s
CI/CD Pipeline / Build Docker Images (push) Has been skipped
CI/CD Pipeline / Push to Gitea Registry (push) Has been skipped
CI/CD Pipeline / Deploy to Server (push) Has been skipped
Some checks failed
CI/CD Pipeline / Run Tests (push) Failing after 45s
CI/CD Pipeline / Code Quality Checks (push) Failing after 48s
CI/CD Pipeline / Build Docker Images (push) Has been skipped
CI/CD Pipeline / Push to Gitea Registry (push) Has been skipped
CI/CD Pipeline / Deploy to Server (push) Has been skipped
This commit is contained in:
92
src/templates/admin/edit_inline/report_period_tabs.html
Normal file
92
src/templates/admin/edit_inline/report_period_tabs.html
Normal file
@@ -0,0 +1,92 @@
|
||||
{% load i18n admin_urls static %}
|
||||
<div class="js-inline-admin-formset inline-group mx-report-period-inline" id="{{ inline_admin_formset.formset.prefix }}-group" data-inline-type="stacked" data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
|
||||
<fieldset class="module {{ inline_admin_formset.classes }} card card-outline">
|
||||
<div class="card-body">
|
||||
{{ inline_admin_formset.formset.management_form }}
|
||||
{{ inline_admin_formset.formset.non_form_errors }}
|
||||
|
||||
<div class="mx-report-period-inline__header">
|
||||
<h3 class="mx-report-period-inline__title">{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}</h3>
|
||||
<p class="mx-report-period-inline__hint">Печатные формы сгруппированы по отчетным периодам. Архивные версии доступны только в админке.</p>
|
||||
</div>
|
||||
|
||||
<div class="mx-report-period-inline__nav nav nav-tabs" role="tablist">
|
||||
{% for inline_admin_form in inline_admin_formset %}
|
||||
{% with inline_admin_form.original as record %}
|
||||
{% if record %}
|
||||
{% ifchanged record.report_period_key %}
|
||||
<a
|
||||
class="nav-link {% if forloop.first %}active{% endif %}"
|
||||
id="{{ inline_admin_formset.formset.prefix }}-{{ record.report_period_dom_id }}-tab"
|
||||
data-toggle="tab"
|
||||
href="#{{ inline_admin_formset.formset.prefix }}-{{ record.report_period_dom_id }}"
|
||||
role="tab"
|
||||
aria-controls="{{ inline_admin_formset.formset.prefix }}-{{ record.report_period_dom_id }}"
|
||||
aria-selected="{% if forloop.first %}true{% else %}false{% endif %}"
|
||||
>
|
||||
{{ record.report_period_display }}
|
||||
</a>
|
||||
{% endifchanged %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% empty %}
|
||||
<span class="mx-report-period-inline__empty">Отчетность пока не загружена.</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="tab-content mx-report-period-inline__content">
|
||||
{% for inline_admin_form in inline_admin_formset %}
|
||||
{% with inline_admin_form.original as record %}
|
||||
{% if record %}
|
||||
{% ifchanged record.report_period_key %}
|
||||
{% if not forloop.first %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div
|
||||
class="tab-pane fade {% if forloop.first %}show active{% endif %}"
|
||||
id="{{ inline_admin_formset.formset.prefix }}-{{ record.report_period_dom_id }}"
|
||||
role="tabpanel"
|
||||
aria-labelledby="{{ inline_admin_formset.formset.prefix }}-{{ record.report_period_dom_id }}-tab"
|
||||
>
|
||||
<div class="mx-report-period-inline__cards">
|
||||
{% endifchanged %}
|
||||
<article class="mx-report-period-card{% if not record.is_active_version %} mx-report-period-card--archived{% endif %}">
|
||||
<header class="mx-report-period-card__header">
|
||||
<div>
|
||||
<p class="mx-report-period-card__eyebrow">{{ record.report_period_short_label }}</p>
|
||||
<h4 class="mx-report-period-card__title">{{ record.version_label }}</h4>
|
||||
</div>
|
||||
<div class="mx-report-period-card__meta">
|
||||
<span class="mx-report-period-card__badge{% if record.is_active_version %} is-current{% else %} is-archived{% endif %}">
|
||||
{% if record.is_active_version %}Актуальная{% else %}Архив{% endif %}
|
||||
</span>
|
||||
<span class="mx-report-period-card__badge">Batch {{ record.load_batch }}</span>
|
||||
{% if record.superseded_by_batch %}
|
||||
<span class="mx-report-period-card__badge">Заменен batch {{ record.superseded_by_batch }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{% if inline_admin_form.form.non_field_errors %}
|
||||
{{ inline_admin_form.form.non_field_errors }}
|
||||
{% endif %}
|
||||
|
||||
{% for fieldset in inline_admin_form %}
|
||||
{% include "admin/includes/fieldset.html" %}
|
||||
{% endfor %}
|
||||
|
||||
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
|
||||
{% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %}
|
||||
</article>
|
||||
{% if forloop.last %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
107
src/templates/admin/includes/fieldset.html
Normal file
107
src/templates/admin/includes/fieldset.html
Normal file
@@ -0,0 +1,107 @@
|
||||
{% load jazzmin %}
|
||||
{% if card %}
|
||||
<div class="card {{ fieldset.classes|cut:"collapse" }}">
|
||||
{% if card_header and fieldset.name %}
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
<strong>{{ fieldset.name }}</strong>{% if fieldset.description %} - <i>{{ fieldset.description }}</i>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% elif fieldset.description %}
|
||||
<div class="card-header">
|
||||
<div class="card-title">
|
||||
{{ fieldset.description }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="p-5{% if fieldset.name %} card-body{% endif %}">
|
||||
{% endif %}
|
||||
|
||||
{% for line in fieldset %}
|
||||
{% if line.fields|length_is:'1' %}
|
||||
{% for field in line %}
|
||||
{% if field.field.name == "paper_form_preview" %}
|
||||
<div class="form-group mx-paper-form-row{% if line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}">
|
||||
<div class="mx-paper-form-field{% if field.field.is_hidden %} hidden{% endif %}">
|
||||
{% if field.is_readonly %}
|
||||
<div class="readonly">{{ field.contents }}</div>
|
||||
{% else %}
|
||||
{{ field.field }}
|
||||
{% endif %}
|
||||
<div class="help-block red">
|
||||
{% if not field.is_readonly %}{{ field.errors }}{% endif %}
|
||||
</div>
|
||||
{% if field.field.help_text %}
|
||||
<div class="help-block">{{ field.field.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
<div class="help-block text-red">
|
||||
{{ line.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-group{% if line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %} field-{{ field.field.name }}">
|
||||
<div class="row">
|
||||
<label class="col-sm-3 text-left" for="id_{{ field.field.name }}">
|
||||
{{ field.field.label|capfirst }}
|
||||
{% if field.field.field.required %}
|
||||
<span class="text-red">* </span>
|
||||
{% endif %}
|
||||
</label>
|
||||
<div class="col-sm-7 field-{{ field.field.name }}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}{% if field.is_checkcard %} checkcard-row{% endif %}">
|
||||
{% if field.is_readonly %}
|
||||
<div class="readonly">{{ field.contents }}</div>
|
||||
{% else %}
|
||||
{{ field.field }}
|
||||
{% endif %}
|
||||
<div class="help-block red">
|
||||
{% if not field.is_readonly %}{{ field.errors }}{% endif %}
|
||||
</div>
|
||||
{% if field.field.help_text %}
|
||||
<div class="help-block">{{ field.field.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
<div class="help-block text-red">
|
||||
{{ line.errors }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="form-group{% if line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
|
||||
<div class="row">
|
||||
{% for field in line %}
|
||||
<label class="{% if forloop.counter != 1 %}col-auto {% else %}col-sm-3 {% endif %}text-left" for="id_{{ field.field.name }}">
|
||||
{{ field.field.label|capfirst }}
|
||||
{% if field.field.field.required %}
|
||||
<span class="text-red">* </span>
|
||||
{% endif %}
|
||||
</label>
|
||||
<div class="col-auto fieldBox{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}{% if field.is_checkcard %} checkcard-row{% endif %}">
|
||||
{% if field.is_readonly %}
|
||||
<div class="readonly">{{ field.contents }}</div>
|
||||
{% else %}
|
||||
{{ field.field }}
|
||||
{% endif %}
|
||||
<div class="help-block red">
|
||||
{% if not field.is_readonly %}{{ field.errors }}{% endif %}
|
||||
</div>
|
||||
{% if field.field.help_text %}
|
||||
<div class="help-block">{{ field.field.help_text|safe }}</div>
|
||||
{% endif %}
|
||||
<div class="help-block text-red">
|
||||
{% if forloop.first %}{{ line.errors }}{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if card %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
468
src/templates/admin/index.html
Normal file
468
src/templates/admin/index.html
Normal file
@@ -0,0 +1,468 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n static jazzmin log %}
|
||||
|
||||
{% block bodyclass %}{{ block.super }} dashboard mx-dashboard-page{% endblock %}
|
||||
|
||||
{% block extrastyle %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" href="{% static 'admin/css/state-corp-admin-dashboard.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content_title %}{% trans 'Dashboard' %}{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{% url 'admin:index' %}">{% trans 'Home' %}</a></li>
|
||||
<li class="breadcrumb-item">{% trans 'Dashboard' %}</li>
|
||||
</ol>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% get_side_menu using="app_list" as dashboard_list %}
|
||||
|
||||
<div class="mx-dashboard">
|
||||
<section class="mx-hero">
|
||||
<div class="mx-hero__copy">
|
||||
<p class="mx-eyebrow">Панель управления</p>
|
||||
<h1 class="mx-hero__title">Панель форм и импортов</h1>
|
||||
<p class="mx-hero__lead">
|
||||
Живой обзор по справочнику организаций, наполнению форм Ф-1...Ф-6
|
||||
и последним импортам без переключения между разделами админки.
|
||||
</p>
|
||||
|
||||
<div class="mx-hero__facts">
|
||||
{% for item in admin_dashboard_data.hero_stats %}
|
||||
<div class="mx-hero__fact">
|
||||
<span class="mx-hero__fact-label">{{ item.label }}</span>
|
||||
<strong class="mx-hero__fact-value">
|
||||
{% if item.value is not None %}
|
||||
{% if item.is_datetime %}
|
||||
{{ item.value|date:"d.m.Y H:i" }}
|
||||
{% else %}
|
||||
{{ item.value }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
нет данных
|
||||
{% endif %}
|
||||
</strong>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-hero__visual">
|
||||
<div class="mx-ring-card">
|
||||
<div
|
||||
class="mx-ring-chart"
|
||||
style="background: {{ admin_dashboard_data.source_mix.background }};"
|
||||
>
|
||||
<div class="mx-ring-chart__center">
|
||||
<span>всего записей</span>
|
||||
<strong>{{ admin_dashboard_data.source_mix.total_records_label }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx-ring-card__legend">
|
||||
{% if admin_dashboard_data.source_mix.segments %}
|
||||
{% for segment in admin_dashboard_data.source_mix.segments %}
|
||||
<div class="mx-ring-card__legend-item">
|
||||
<span
|
||||
class="mx-dot"
|
||||
style="background: {{ segment.color }};"
|
||||
></span>
|
||||
<div>
|
||||
<strong>{{ segment.title }}</strong>
|
||||
<span>{{ segment.value }} · {{ segment.share }}%</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="mx-empty-state">
|
||||
Диаграмма появится после первой загрузки данных из источников.
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mx-overview-grid">
|
||||
{% for card in admin_dashboard_data.overview_cards %}
|
||||
<article class="mx-stat-card mx-stat-card--{{ card.tone }}">
|
||||
<span class="mx-stat-card__label">{{ card.label }}</span>
|
||||
<strong class="mx-stat-card__value">{{ card.value }}</strong>
|
||||
<p class="mx-stat-card__caption">{{ card.caption }}</p>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
||||
<section class="mx-panel mx-period-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Отчетные периоды</p>
|
||||
<h2>Какие формы загружены по периодам</h2>
|
||||
</div>
|
||||
<p class="mx-panel__note">
|
||||
{{ admin_dashboard_data.period_chart.note }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% if admin_dashboard_data.period_chart.rows %}
|
||||
<div class="mx-period-grid-wrap">
|
||||
<div class="mx-period-grid">
|
||||
<div class="mx-period-grid__row mx-period-grid__row--head">
|
||||
<span class="mx-period-grid__head-cell">Период</span>
|
||||
{% for header in admin_dashboard_data.period_chart.headers %}
|
||||
<span class="mx-period-grid__head-cell mx-period-grid__head-cell--form">
|
||||
{{ header.short_title }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
<span class="mx-period-grid__head-cell">Комплект</span>
|
||||
</div>
|
||||
|
||||
{% for row in admin_dashboard_data.period_chart.rows %}
|
||||
<article class="mx-period-grid__row">
|
||||
<div class="mx-period-row__period">
|
||||
<strong>{{ row.period_label }}</strong>
|
||||
<span>{{ row.summary }}</span>
|
||||
<small>{{ row.note }}</small>
|
||||
</div>
|
||||
|
||||
{% for cell in row.forms %}
|
||||
<div
|
||||
class="mx-period-cell {% if cell.is_loaded %}mx-period-cell--loaded{% else %}mx-period-cell--empty{% endif %}"
|
||||
style="--mx-period-accent: {{ cell.color }};"
|
||||
>
|
||||
<strong>{{ cell.headline }}</strong>
|
||||
<small>{{ cell.caption }}</small>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="mx-period-row__summary">
|
||||
<strong>{{ row.loaded_forms_label }}</strong>
|
||||
<span>{{ row.records_total_label }} записей</span>
|
||||
<div class="mx-bar-track">
|
||||
<span style="width: {{ row.bar_width }}%;"></span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="mx-empty-state">
|
||||
После первых загрузок форм здесь появится матрица по отчетным периодам.
|
||||
</p>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<section class="mx-tabs">
|
||||
<input
|
||||
class="mx-tab-toggle"
|
||||
type="radio"
|
||||
name="mx-dashboard-tab"
|
||||
id="mx-tab-overview"
|
||||
checked
|
||||
>
|
||||
<input
|
||||
class="mx-tab-toggle"
|
||||
type="radio"
|
||||
name="mx-dashboard-tab"
|
||||
id="mx-tab-analytics"
|
||||
>
|
||||
<input
|
||||
class="mx-tab-toggle"
|
||||
type="radio"
|
||||
name="mx-dashboard-tab"
|
||||
id="mx-tab-admin"
|
||||
>
|
||||
|
||||
<div class="mx-tab-nav" role="tablist" aria-label="Разделы dashboard">
|
||||
<label for="mx-tab-overview" class="mx-tab-label">Обзор</label>
|
||||
<label for="mx-tab-analytics" class="mx-tab-label">Аналитика</label>
|
||||
<label for="mx-tab-admin" class="mx-tab-label">Админка</label>
|
||||
</div>
|
||||
|
||||
<div class="mx-tab-panels">
|
||||
<div class="mx-tab-panel mx-tab-panel--overview">
|
||||
<section class="mx-main-grid">
|
||||
<div class="mx-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Источники</p>
|
||||
<h2>Покрытие по формам</h2>
|
||||
</div>
|
||||
<p class="mx-panel__note">
|
||||
{{ admin_dashboard_data.source_cards_note }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mx-source-grid">
|
||||
{% for card in admin_dashboard_data.source_cards %}
|
||||
<article
|
||||
class="mx-source-card mx-tone--{{ card.status_tone }}"
|
||||
style="--mx-accent: {{ card.color }}; --mx-bar-value: {{ card.records_bar_width }}%; --mx-org-bar-value: {{ card.organizations_bar_width }}%;"
|
||||
>
|
||||
<div class="mx-source-card__top">
|
||||
<span class="mx-status-pill">{{ card.status_label }}</span>
|
||||
<span class="mx-source-card__share">{{ card.records_share }}%</span>
|
||||
</div>
|
||||
|
||||
<h3>{{ card.title }}</h3>
|
||||
<p>{{ card.description }}</p>
|
||||
|
||||
<div class="mx-source-card__metrics">
|
||||
<div>
|
||||
<span>Записей</span>
|
||||
<strong>{{ card.records_count_label }}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Организаций</span>
|
||||
<strong>{{ card.organizations_count_label }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-meter">
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="mx-meter mx-meter--soft">
|
||||
<span></span>
|
||||
</div>
|
||||
|
||||
<div class="mx-source-card__footer">
|
||||
{% if card.last_updated_at %}
|
||||
<span>Обновлено {{ card.last_updated_at|timesince }} назад</span>
|
||||
{% else %}
|
||||
<span>Ещё не загружалось</span>
|
||||
{% endif %}
|
||||
<span>{{ card.metrics_scope_label }}</span>
|
||||
{% if card.error_message %}
|
||||
<span class="mx-source-card__error">{{ card.error_message|truncatechars:80 }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</article>
|
||||
{% empty %}
|
||||
<p class="mx-empty-state">Подключённых источников пока нет.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="mx-side-stack">
|
||||
<section class="mx-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Быстрые действия</p>
|
||||
<h2>Рабочие входы</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-action-list">
|
||||
{% for action in admin_dashboard_data.quick_actions %}
|
||||
<a href="{{ action.url }}" class="mx-action-card">
|
||||
<strong>{{ action.label }}</strong>
|
||||
<span>{{ action.description }}</span>
|
||||
</a>
|
||||
{% empty %}
|
||||
<p class="mx-empty-state">Быстрые действия недоступны.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mx-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Поток загрузок</p>
|
||||
<h2>Последние события</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-feed-list">
|
||||
{% for event in admin_dashboard_data.activity_feed %}
|
||||
<article class="mx-feed-item mx-tone--{{ event.tone }}">
|
||||
<div class="mx-feed-item__meta">
|
||||
<span class="mx-feed-item__kind">{{ event.kind }}</span>
|
||||
<time>{{ event.timestamp|date:"d.m.Y H:i" }}</time>
|
||||
</div>
|
||||
<strong>{{ event.title }}</strong>
|
||||
<p>{{ event.meta }}</p>
|
||||
<span class="mx-feed-item__note">{{ event.note|truncatechars:80 }}</span>
|
||||
</article>
|
||||
{% empty %}
|
||||
<p class="mx-empty-state">После первых импортов здесь появится рабочая лента.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
</aside>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="mx-tab-panel mx-tab-panel--analytics">
|
||||
<section class="mx-split-grid">
|
||||
<div class="mx-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Формы</p>
|
||||
<h2>Где больше записей</h2>
|
||||
</div>
|
||||
<p class="mx-panel__note">
|
||||
Раскладка показывает объём записей по каждой форме и долю охвата организаций.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mx-bar-list">
|
||||
{% for form in admin_dashboard_data.form_rows %}
|
||||
<article class="mx-bar-item">
|
||||
<div class="mx-bar-item__head">
|
||||
<div>
|
||||
<strong>{{ form.name }}</strong>
|
||||
<span>{{ form.note }}</span>
|
||||
</div>
|
||||
<strong>{{ form.value }}</strong>
|
||||
</div>
|
||||
<div class="mx-bar-track">
|
||||
<span style="width: {{ form.bar_width }}%;"></span>
|
||||
</div>
|
||||
</article>
|
||||
{% empty %}
|
||||
<p class="mx-empty-state">Формы ещё не загружались.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Организации</p>
|
||||
<h2>Топ по покрытию формами</h2>
|
||||
</div>
|
||||
<p class="mx-panel__note">
|
||||
{{ admin_dashboard_data.organization_rows_note }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mx-bar-list mx-bar-list--regions">
|
||||
{% for organization in admin_dashboard_data.organization_rows %}
|
||||
<article class="mx-bar-item">
|
||||
<div class="mx-bar-item__head">
|
||||
<div>
|
||||
<strong>{{ organization.name }}</strong>
|
||||
<span>
|
||||
{{ organization.records_count_label }} записей
|
||||
· {{ organization.note }}
|
||||
</span>
|
||||
</div>
|
||||
<strong>{{ organization.forms_count_label }} форм</strong>
|
||||
</div>
|
||||
<div class="mx-bar-track mx-bar-track--violet">
|
||||
<span style="width: {{ organization.bar_width }}%;"></span>
|
||||
</div>
|
||||
</article>
|
||||
{% empty %}
|
||||
<p class="mx-empty-state">Рейтинг появится после первых загрузок форм.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="mx-tab-panel mx-tab-panel--admin">
|
||||
<section class="mx-split-grid">
|
||||
<div class="mx-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Разделы</p>
|
||||
<h2>Рабочие зоны админки</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-app-grid">
|
||||
{% for app in dashboard_list %}
|
||||
<article class="mx-app-card">
|
||||
<div class="mx-app-card__head">
|
||||
<h3>{{ app.name }}</h3>
|
||||
<span>{{ app.models|length }} моделей</span>
|
||||
</div>
|
||||
|
||||
<div class="mx-app-card__body">
|
||||
{% for model in app.models %}
|
||||
<div class="mx-app-model">
|
||||
<span class="mx-app-model__name">
|
||||
{% if model.url %}
|
||||
<a href="{{ model.url }}">{{ model.name }}</a>
|
||||
{% else %}
|
||||
{{ model.name }}
|
||||
{% endif %}
|
||||
</span>
|
||||
|
||||
<div class="mx-app-model__actions">
|
||||
{% if model.add_url %}
|
||||
<a href="{{ model.add_url }}" class="mx-mini-button">Добавить</a>
|
||||
{% endif %}
|
||||
{% if model.url %}
|
||||
<a href="{{ model.url }}" class="mx-mini-button mx-mini-button--ghost">
|
||||
{% if model.view_only %}Открыть{% else %}Управлять{% endif %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</article>
|
||||
{% empty %}
|
||||
<p class="mx-empty-state">Доступных разделов не найдено.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-panel">
|
||||
<div class="mx-panel__header">
|
||||
<div>
|
||||
<p class="mx-eyebrow">Audit</p>
|
||||
<h2>Последние действия в админке</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% get_admin_log 8 as admin_log for_user user %}
|
||||
<div class="mx-feed-list">
|
||||
{% for entry in admin_log %}
|
||||
<article class="mx-feed-item mx-tone--cyan">
|
||||
<div class="mx-feed-item__meta">
|
||||
<span class="mx-feed-item__kind">
|
||||
{% if entry.is_change %}
|
||||
Изменение
|
||||
{% elif entry.is_deletion %}
|
||||
Удаление
|
||||
{% elif entry.is_addition %}
|
||||
Создание
|
||||
{% else %}
|
||||
Действие
|
||||
{% endif %}
|
||||
</span>
|
||||
<time>{{ entry.action_time|date:"d.m.Y H:i" }}</time>
|
||||
</div>
|
||||
<strong>
|
||||
{% if entry.is_deletion or not entry.get_admin_url %}
|
||||
{{ entry.object_repr }}
|
||||
{% else %}
|
||||
<a href="{{ entry.get_admin_url }}">{{ entry.object_repr }}</a>
|
||||
{% endif %}
|
||||
</strong>
|
||||
<p>
|
||||
{% if entry.model %}
|
||||
{{ entry.model|capfirst }}
|
||||
{% else %}
|
||||
Объект без модели
|
||||
{% endif %}
|
||||
</p>
|
||||
<span class="mx-feed-item__note">{{ entry }}</span>
|
||||
</article>
|
||||
{% empty %}
|
||||
<p class="mx-empty-state">История действий пока пустая.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,9 @@
|
||||
{% extends "admin/change_list.html" %}
|
||||
{% load admin_urls %}
|
||||
|
||||
{% block object-tools-items %}
|
||||
<a href="{{ upload_backup_url }}" class="btn btn-primary mr-2">
|
||||
Импортировать backup реестров
|
||||
</a>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,56 @@
|
||||
{% extends "admin/base_site.html" %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{% url 'admin:index' %}">Главная</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ changelist_url }}">Загрузки реестров</a></li>
|
||||
<li class="breadcrumb-item active">Импорт backup</li>
|
||||
</ol>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_title %}Импорт backup реестров{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<p class="text-muted">
|
||||
Импорт выполняется синхронно. Загрузите архив <code>.zip</code> или файл
|
||||
<code>.bin</code>, экспортированный из внешней системы.
|
||||
</p>
|
||||
<p class="text-muted">
|
||||
Файл должен содержать зашифрованный backup с данными реестров.
|
||||
Организаций в текущем справочнике: {{ organizations_count }}.
|
||||
</p>
|
||||
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label for="id_files">Backup файлы</label>
|
||||
<input
|
||||
type="file"
|
||||
name="files"
|
||||
id="id_files"
|
||||
class="form-control"
|
||||
accept=".zip,.bin"
|
||||
multiple
|
||||
required
|
||||
/>
|
||||
<small class="form-text text-muted">
|
||||
Поддерживаются архивы <code>.zip</code> с вложенным <code>.bin</code>
|
||||
и прямые файлы <code>.bin</code>. Для расшифровки используется
|
||||
<code>BACKUP_ENCRYPTION_KEY</code>.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center">
|
||||
<input type="submit" value="Загрузить" class="btn btn-primary mr-2" />
|
||||
<a href="{{ changelist_url }}" class="btn btn-outline-secondary">Отмена</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user