Initial commit

This commit is contained in:
2025-09-04 11:27:16 +03:00
commit c1a75f783a
29 changed files with 2153 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
{% extends "layout.html" %}
{% block content %}
<h2 class="mb-4">Вопросы категории: <span class="text-primary">{{ product.name }}</span></h2>
<form method="post" class="mb-4">
<div class="row g-2">
<div class="col-md-10">
<textarea name="question_text" class="form-control" placeholder="Текст вопроса" rows="1" required></textarea>
</div>
<div class="col-md-2 d-grid">
<button type="submit" class="btn btn-success"> Добавить</button>
</div>
</div>
</form>
<ul class="list-group shadow-sm">
{% for feature in features %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>{{ feature.name }}</strong><br>
<small class="text-muted">{{ feature.question_text }}</small>
</div>
<form method="post" action="{{ url_for('delete_feature', feature_id=feature.id, product_id=product.id) }}"
onsubmit="return confirm('Удалить вопрос «{{ feature.name }}»?');">
<button class="btn btn-sm btn-outline-danger">🗑 Удалить</button>
</form>
</li>
{% else %}
<li class="list-group-item text-center text-muted">Нет добавленных вопросов</li>
{% endfor %}
</ul>
<a href="{{ url_for('manage_products', survey_id=product.survey_type.id) }}" class="btn btn-link mt-4">← Назад к категориям</a>
{% endblock %}

View File

@@ -0,0 +1,33 @@
{% extends "layout.html" %}
{% block content %}
<h2 class="mb-4">Платформы опроса: {{ survey.name }}</h2>
<form method="post" class="mb-4">
<div class="input-group shadow-sm">
<input type="text" name="name" class="form-control" placeholder="Название платформы" required>
<button type="submit" class="btn btn-success"> Добавить</button>
</div>
</form>
<div class="list-group shadow-sm">
{% for platform in platforms %}
<div class="list-group-item d-flex justify-content-between align-items-center">
<strong>{{ platform.name }}</strong>
<form method="post"
action="{{ url_for('delete_platform_by_survey', survey_id=survey.id, platform_id=platform.id) }}"
onsubmit="return confirm('Удалить платформу «{{ platform.name }}»?');">
<button type="submit" class="btn btn-sm btn-outline-danger">🗑</button>
</form>
</div>
{% else %}
<div class="list-group-item text-muted text-center">Платформ пока нет</div>
{% endfor %}
</div>
<div class="mt-4 d-flex justify-content-between">
<a href="{{ url_for('manage_support_by_survey', survey_id=survey.id) }}" class="btn btn-outline-secondary">
⚙ Управление поддержкой функциональности
</a>
<a href="{{ url_for('manage_surveys') }}" class="btn btn-link">← Назад к опросам</a>
</div>
{% endblock %}

View File

@@ -0,0 +1,32 @@
{% extends "layout.html" %}
{% block content %}
<h2 class="mb-4">Категории опроса: <span class="text-primary">{{ survey.name }}</span></h2>
<form method="post" class="mb-4">
<div class="input-group shadow-sm">
<input type="text" name="name" class="form-control" placeholder="Название категории (например: Базовые возможности)" required>
<button type="submit" class="btn btn-success"> Добавить</button>
</div>
</form>
<div class="list-group shadow-sm">
{% for product in products %}
<div class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>{{ product.name }}</strong>
</div>
<div class="d-flex gap-2">
<a href="{{ url_for('manage_features', product_id=product.id) }}" class="btn btn-sm btn-outline-primary">Вопросы</a>
<form method="post" action="{{ url_for('delete_product', product_id=product.id, survey_id=survey.id) }}"
onsubmit="return confirm('Удалить категорию «{{ product.name }}»?');">
<button class="btn btn-sm btn-outline-danger">🗑</button>
</form>
</div>
</div>
{% else %}
<div class="list-group-item text-muted text-center">Нет категорий</div>
{% endfor %}
</div>
<a href="{{ url_for('manage_surveys') }}" class="btn btn-link mt-4">← Назад к опросникам</a>
{% endblock %}

View File

@@ -0,0 +1,37 @@
{% extends "layout.html" %}
{% block content %}
<h2 class="mb-4">Матрица поддержки: {{ survey.name }}</h2>
<form method="post">
<table class="table table-bordered table-sm align-middle">
<thead class="table-light">
<tr>
<th>Функция</th>
{% for platform in platforms %}
<th class="text-center">{{ platform.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for feature in features %}
<tr>
<td>
<strong>{{ feature.name }}</strong><br>
<small>{{ feature.question_text }}</small>
</td>
{% for platform in platforms %}
<td class="text-center">
<input type="checkbox"
name="support_{{ platform.id }}_{{ feature.id }}"
{% if support[platform.id][feature.id] %}checked{% endif %}>
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<button type="submit" class="btn btn-success mt-3">Сохранить</button>
</form>
<a href="{{ url_for('manage_platforms_by_survey', survey_id=survey.id) }}" class="btn btn-link mt-4">← Назад к платформам</a>
{% endblock %}

View File

@@ -0,0 +1,48 @@
{% extends "layout.html" %}
{% block content %}
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="mb-0">Матрица поддержки: {{ survey.name }}</h2>
<a href="{{ url_for('manage_platforms_by_survey', survey_id=survey.id) }}" class="btn btn-outline-secondary">← Назад к платформам</a>
</div>
<form method="post">
<div class="table-responsive">
<table class="table table-bordered table-hover align-middle">
<thead class="table-dark text-center">
<tr>
<th class="text-start">Функция</th>
{% for platform in platforms %}
<th>{{ platform.name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for feature in features %}
<tr>
<td>
<strong>{{ feature.question_text }}</strong><br>
<!-- <span class="text-muted small">{{ feature.question_text }}</span>-->
</td>
{% for platform in platforms %}
<td class="text-center">
<div class="form-check form-switch d-flex justify-content-center">
<input class="form-check-input"
type="checkbox"
role="switch"
name="support_{{ platform.id }}_{{ feature.id }}"
{% if support[platform.id][feature.id] %}checked{% endif %}>
</div>
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-between mt-4">
<button type="submit" class="btn btn-primary">💾 Сохранить</button>
<a href="{{ url_for('choose_survey') }}" class="btn btn-link">На главную</a>
</div>
</form>
{% endblock %}

BIN
templates/admin/survey.db Normal file

Binary file not shown.

View File

@@ -0,0 +1,51 @@
{% extends "layout.html" %}
{% block content %}
<h2 class="mb-4">Опросники</h2>
<form method="post" class="mb-4">
<div class="input-group">
<input type="text" name="name" class="form-control" placeholder="Название опроса" required>
<button type="submit" class="btn btn-primary">Создать</button>
</div>
</form>
{% for survey in surveys %}
<div class="card mb-4 p-3">
<h5>{{ survey.name }}</h5>
<!-- Старая админская панель -->
<div class="btn-group mb-3">
<a href="{{ url_for('manage_products', survey_id=survey.id) }}" class="btn btn-sm btn-outline-secondary">Категории и вопросы</a>
<a href="{{ url_for('manage_platforms_by_survey', survey_id=survey.id) }}" class="btn btn-sm btn-outline-primary">Продукты</a>
<a href="{{ url_for('manage_support_by_survey', survey_id=survey.id) }}" class="btn btn-sm btn-outline-success">Матрица</a>
<form method="post" action="{{ url_for('delete_survey', survey_id=survey.id) }}" onsubmit="return confirm('Удалить опрос {{ survey.name }}?')">
<button type="submit" class="btn btn-sm btn-danger">Удалить</button>
</form>
</div>
<!-- Назначения пользователям -->
{% if current_user.is_admin %}
<!-- Назначения пользователям (только для админа) -->
<form method="POST" action="{{ url_for('assign_bulk_surveys') }}">
<input type="hidden" name="survey_id" value="{{ survey.id }}">
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-4 g-2">
{% for user in users %}
<div class="form-check col">
<input class="form-check-input" type="checkbox" name="user_ids" value="{{ user.id }}"
id="user{{ user.id }}_survey{{ survey.id }}"
{% if user.id in assignments[survey.id] %}checked{% endif %}>
<label class="form-check-label" for="user{{ user.id }}_survey{{ survey.id }}">
{{ user.username }} ({{ user.full_name or "без ФИО" }})
</label>
</div>
{% endfor %}
</div>
<div class="mt-2">
<button class="btn btn-sm btn-primary">Сохранить назначения</button>
</div>
</form>
{% endif %}
</div>
{% endfor %}
{% endblock %}

View File

@@ -0,0 +1,61 @@
{% extends "layout.html" %}
{% block content %}
<div class="container mt-4">
<h2>Доступные опросы</h2>
{% if current_user.is_admin %}
{% for survey in surveys %}
<div class="card mb-4 p-3">
<h5>{{ survey.name }}</h5>
<!-- Кнопка пройти -->
<a href="{{ url_for('show_quiz', survey_id=survey.id) }}" class="btn btn-sm btn-primary mb-2">Пройти</a>
<!-- Расшаривание пользователям -->
<form method="POST" action="{{ url_for('assign_user_survey_bulk') }}">
<input type="hidden" name="survey_id" value="{{ survey.id }}">
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-4 g-2">
{% for user in users %}
<div class="form-check col">
<input class="form-check-input" type="checkbox" name="user_ids"
value="{{ user.id }}"
id="survey{{ survey.id }}_user{{ user.id }}"
{% if survey.id in assignments and user.id in assignments[survey.id] %}checked{% endif %}>
<label class="form-check-label" for="survey{{ survey.id }}_user{{ user.id }}">
{{ user.username }} ({{ user.full_name or "без ФИО" }})
</label>
</div>
{% endfor %}
</div>
<div class="mt-2">
<button class="btn btn-sm btn-warning">Сохранить назначения</button>
</div>
</form>
</div>
{% endfor %}
{% else %}
{% for us in surveys %}
<div class="list-group mb-2">
<div class="list-group-item d-flex justify-content-between align-items-center">
<div class="fw-bold">{{ us.survey_type.name }}</div>
<div class="btn-group">
<a href="{{ url_for('show_quiz', survey_id=us.survey_type.id) }}" class="btn btn-sm btn-primary">Пройти</a>
<button class="btn btn-sm btn-outline-secondary" data-bs-toggle="collapse" data-bs-target="#send{{ us.id }}">Отправить</button>
</div>
</div>
<div class="collapse p-3 border rounded" id="send{{ us.id }}">
<form id="send-survey-form" method="POST" action="{{ url_for('send_survey', survey_id=us.id) }}">
<input type="email" name="email" class="form-control mb-2" placeholder="Email" required>
<div class="form-check"><input class="form-check-input" type="checkbox" name="show_result"> Показывать результат</div>
<div class="form-check"><input class="form-check-input" type="checkbox" name="ask_full_name"> Указать ФИО</div>
<div class="form-check"><input class="form-check-input" type="checkbox" name="ask_phone"> Указать телефон</div>
<div class="form-check"><input class="form-check-input" type="checkbox" name="ask_organization"> Указать организацию</div>
<button class="btn btn-success btn-sm mt-2">Отправить</button>
</form>
</div>
</div>
{% endfor %}
{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,61 @@
{% extends "layout.html" %}
{% block content %}
<div class="container my-5">
<h2 class="text-center mb-4">Опрос: {{ survey.survey_type.name }}</h2>
<form method="POST">
{% if invite.ask_full_name or invite.ask_phone or invite.ask_organization %}
<div class="card mb-4">
<div class="card-header bg-info text-white fw-bold">
Информация о респонденте
</div>
<div class="card-body">
{% if invite.ask_full_name %}
<div class="mb-3">
<label for="full_name" class="form-label">ФИО</label>
<input type="text" name="full_name" id="full_name" class="form-control" required>
</div>
{% endif %}
{% if invite.ask_phone %}
<div class="mb-3">
<label for="phone" class="form-label">Телефон</label>
<input type="text" name="phone" id="phone" class="form-control" required>
</div>
{% endif %}
{% if invite.ask_organization %}
<div class="mb-3">
<label for="organization" class="form-label">Наименование организации</label>
<input type="text" name="organization" id="organization" class="form-control" required>
</div>
{% endif %}
</div>
</div>
{% endif %}
{% for group, items in questions.items() %}
<div class="card mb-4 shadow-sm">
<div class="card-header bg-primary text-white fw-bold">
{{ group }}
</div>
<div class="card-body">
{% for key, text in items.items() %}
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" name="{{ key }}" id="{{ key }}">
<label class="form-check-label" for="{{ key }}">{{ text }}</label>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
<div class="mb-4">
<label for="comment" class="form-label">Комментарий</label>
<textarea name="comment" id="comment" class="form-control" rows="4" placeholder="Оставьте ваш комментарий..."></textarea>
</div>
<div class="text-center">
<button type="submit" class="btn btn-primary btn-lg" id="submitBtn">
Отправить
</button>
</div>
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,44 @@
{% extends "layout.html" %}
{% block content %}
<div class="container mt-4">
<h2 class="text-center mb-4">Результат сравнения платформ</h2>
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow-sm">
<div class="card-body">
<h5 class="mb-3">Процент соответствия платформ:</h5>
<ul class="list-group mb-4">
{% for platform, score in scores.items() %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ platform }}
<span class="badge bg-primary rounded-pill">{{ score }}%</span>
</li>
{% endfor %}
</ul>
<h5 class="mb-3">Неподдерживаемые функции:</h5>
{% for platform, features in unsupported_features.items() %}
<div class="mb-3">
<strong>{{ platform }}:</strong>
{% if features %}
<ul class="mt-1">
{% for f in features %}
<li>{{ f }}</li>
{% endfor %}
</ul>
{% else %}
<p class="text-success mb-0">Все функции поддерживаются</p>
{% endif %}
</div>
{% endfor %}
<div class="text-end">
<a href="https://mont.ru" class="btn btn-outline-secondary mt-4">Перейти на сайт МОНТ</a>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,34 @@
{% extends "layout.html" %}
{% block content %}
<div class="container mt-5">
<div class="text-center">
<h2 class="text-success mb-3">Спасибо за участие!</h2>
<p class="lead">Ваши ответы сохранены.</p>
{% if show_result %}
<hr>
<h4>Результаты:</h4>
<ul class="list-group mb-3">
{% for platform, percent in scores.items() %}
<li class="list-group-item d-flex justify-content-between align-items-center">
{{ platform }}
<span class="badge bg-primary rounded-pill">{{ percent }}%</span>
</li>
{% endfor %}
</ul>
<h5 class="text-danger">Неподдерживаемые функции:</h5>
{% for platform, feature_list in unsupported.items() %}
{% if feature_list %}
<p><strong>{{ platform }}:</strong></p>
<ul>
{% for text in feature_list %}
<li>{{ text }}</li>
{% endfor %}
</ul>
{% endif %}
{% endfor %}
{% endif %}
</div>
</div>
{% endblock %}

106
templates/layout.html Normal file
View File

@@ -0,0 +1,106 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>{{ title or "Админка" }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
<style>
body {
background-color: #f8f9fa;
font-family: 'Inter', sans-serif;
}
.navbar {
background-color: #e9f6ff !important;
padding: 0.75rem 1.5rem;
border-radius: 0 0 10px 10px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
}
.navbar-brand {
font-weight: 600;
font-size: 1.3rem;
color: #000 !important;
}
.btn {
transition: all 0.3s ease;
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.container {
max-width: 960px;
}
</style>
</head>
<body>
<nav class="navbar navbar-expand-lg">
<div class="container">
<a class="navbar-brand d-flex align-items-center" href="{{ url_for('choose_survey') }}">
<img src="{{ url_for('static', filename='mont.png') }}" height="40" class="me-2">
<span>Опросник</span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarNav" aria-controls="navbarNav"
aria-expanded="false" aria-label="Меню">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link{% if request.path.startswith('/quiz') %} active{% endif %}" href="{{ url_for('choose_survey') }}">Опросы</a>
</li>
{% if current_user.is_authenticated %}
<li class="nav-item">
<a class="nav-link{% if request.path.startswith('/admin') %} active{% endif %}" href="{{ url_for('manage_surveys') }}">Админка</a>
</li>
<li class="nav-item">
<a class="nav-link{% if request.path.startswith('/dashboard') %} active{% endif %}" href="{{ url_for('dashboard') }}">Отчёты</a>
</li>
<li class="nav-item d-flex align-items-center text-dark ms-3">
<i class="bi bi-person-circle me-1"></i> {{ current_user.full_name or current_user.username }}
{% if current_user.is_admin %}<span class="badge bg-danger ms-2">Админ</span>{% endif %}
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout') }}">Выйти</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link{% if request.path.startswith('/login') %} active{% endif %}" href="{{ url_for('login') }}">Вход</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<main class="container my-5">
{% block content %}{% endblock %}
</main>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
function showLoading(form) {
const button = form.querySelector('button[type="submit"]');
button.disabled = true;
button.innerHTML = `<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span>Отправка...`;
}
</script>
<script>
document.addEventListener('DOMContentLoaded', function () {
const form = document.querySelector('form');
const submitBtn = document.getElementById('submitBtn');
if (form && submitBtn) {
form.addEventListener('submit', function () {
submitBtn.disabled = true;
submitBtn.innerHTML = '⏳ Отправка...';
});
}
});
</script>
</body>
</html>

18
templates/login.html Normal file
View File

@@ -0,0 +1,18 @@
{% extends "layout.html" %}
{% block content %}
<div class="container mt-4">
<h2>Вход</h2>
<form method="POST">
<div class="mb-3">
<label class="form-label">Имя пользователя</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Пароль</label>
<input type="password" name="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Войти</button>
<a href="{{ url_for('register') }}" class="btn btn-link">Регистрация</a>
</form>
</div>
{% endblock %}

27
templates/quiz.html Normal file
View File

@@ -0,0 +1,27 @@
{% extends "layout.html" %}
{% block content %}
<h2 class="mb-4 text-center">Опрос: {{ survey.name }}</h2>
<form method="post" action="{{ url_for('show_quiz', survey_id=survey.id) }}">
{% for category, features in questions.items() %}
<div class="card mb-4 shadow-sm">
<div class="card-header bg-primary text-white fw-semibold fs-5">
{{ category }}
</div>
<div class="card-body">
{% for feature in features %}
<div class="form-check mb-2">
<input class="form-check-input" type="checkbox" value="1" name="feature_{{ feature.id }}" id="f{{ feature.id }}">
<label class="form-check-label" for="f{{ feature.id }}">
{{ feature.question_text }}
</label>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
<div class="text-end">
<button type="submit" class="btn btn-success btn-lg" id="submitBtn">Отправить</button>
</div>
</form>
{% endblock %}

26
templates/register.html Normal file
View File

@@ -0,0 +1,26 @@
{% extends "layout.html" %}
{% block content %}
<div class="container mt-4">
<h2>Регистрация</h2>
<form method="POST">
<div class="mb-3">
<label class="form-label">Имя пользователя</label>
<input type="text" name="username" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">ФИО</label>
<input type="text" name="full_name" class="form-control">
</div>
<div class="mb-3">
<label class="form-label">Email</label>
<input type="email" name="email" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Пароль</label>
<input type="password" name="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Зарегистрироваться</button>
<a href="{{ url_for('login') }}" class="btn btn-link">Уже есть аккаунт?</a>
</form>
</div>
{% endblock %}

132
templates/result.html Normal file
View File

@@ -0,0 +1,132 @@
{% extends "layout.html" %}
{% block content %}
<div class="text-center mb-5">
<h1 class="fw-bold">Результаты выбора платформы</h1>
</div>
<div class="results-container">
<div class="card shadow-sm mb-4 p-4">
<canvas id="platformChart" height="100"></canvas>
</div>
{% for platform, score in scores.items() %}
<div class="card mb-3 shadow-sm">
<div class="card-body">
<h4 class="card-title text-primary mb-2">{{ platform }} — {{ "%.2f"|format(score) }}%</h4>
{% if unsupported_features[platform] %}
<p class="text-danger fw-semibold mb-1">Не поддерживается:</p>
<ul class="text-danger mb-0">
{% for feature in unsupported_features[platform] %}
<li>{{ feature }}</li>
{% endfor %}
</ul>
{% else %}
<p class="text-success mb-0">Все необходимые функции поддерживаются ✅</p>
{% endif %}
</div>
</div>
{% endfor %}
<div class="text-center mt-4">
<button class="btn btn-outline-primary btn-lg" onclick="downloadPDF()">Скачать в PDF</button>
<a class="btn btn-link mt-3 d-block" href="{{ url_for('choose_survey') }}">← Вернуться к выбору</a>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="{{ url_for('static', filename='js/jspdf.roboto.js') }}"></script>
<script>
const labels = {{ chart_labels|tojson }};
const data = {{ chart_data|tojson }};
const scores = {{ scores|tojson }};
const unsupported = {{ unsupported_features|tojson }};
const ctx = document.getElementById('platformChart').getContext('2d');
const platformChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Совпадение (%)',
data: data,
backgroundColor: 'rgba(52, 152, 219, 0.6)',
borderColor: 'rgba(52, 152, 219, 1)',
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true,
max: 100,
title: {
display: true,
text: 'Процент совпадения'
}
},
x: {
title: {
display: true,
text: 'Платформы'
}
}
},
plugins: {
legend: {
display: false
}
}
}
});
async function downloadPDF() {
const { jsPDF } = window.jspdf;
const doc = new jsPDF();
doc.addFileToVFS("Roboto.ttf", roboto_base64);
doc.addFont("Roboto.ttf", "Roboto", "normal");
doc.setFont("Roboto");
doc.setFontSize(18);
doc.text("Результаты выбора платформы", 10, 15);
const chartCanvas = document.getElementById('platformChart');
const chartImage = await html2canvas(chartCanvas);
const chartDataUrl = chartImage.toDataURL('image/png');
doc.addImage(chartDataUrl, 'PNG', 10, 25, 180, 90);
let y = 120;
doc.setFontSize(12);
for (let platform of labels) {
const score = scores[platform].toFixed(2);
doc.text(`${platform}: ${score}%`, 10, y);
y += 8;
const unsupp = unsupported[platform];
if (unsupp && unsupp.length) {
doc.text("Не поддерживается:", 12, y);
y += 8;
for (let f of unsupp) {
doc.text(`- ${f}`, 16, y);
y += 6;
if (y > 270) {
doc.addPage();
y = 20;
}
}
} else {
doc.text("✔ Все необходимые функции поддерживаются", 12, y);
y += 10;
}
}
doc.save("Результаты_платформы.pdf");
}
</script>
{% endblock %}

View File

@@ -0,0 +1,88 @@
{% extends "layout.html" %}
{% block content %}
<div class="container mt-4">
<h2>Мои отправленные опросы</h2>
{% if invites %}
{% for invite in invites %}
<div class="card mb-3 border {% if invite.responded %}border-success bg-light{% else %}border-danger bg-light{% endif %}">
<div class="card-body d-flex justify-content-between align-items-center">
<div>
<strong>{{ invite.survey.survey_type.name }}</strong><br>
<small class="text-muted">Отправлено: {{ invite.sent_at.strftime('%d.%m.%Y %H:%M') }}</small><br>
<small>Кому: {{ invite.recipient_email }}</small><br>
{% if current_user.is_admin %}
<small class="text-muted">Отправитель: {{ invite.survey.user.full_name }} ({{ invite.survey.user.email }})</small>
{% endif %}
</div>
<div class="btn-group">
{% if invite.responded %}
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="collapse" data-bs-target="#r{{ invite.id }}">
Показать результат
</button>
{% endif %}
{% if not invite.responded %}
<form method="POST" action="{{ url_for('send_survey', survey_id=invite.survey.id) }}">
<input type="hidden" name="email" value="{{ invite.recipient_email }}">
<input type="hidden" name="show_result" value="{{ 1 if invite.show_result else 0 }}">
<input type="hidden" name="ask_full_name" value="{{ 1 if invite.ask_full_name else 0 }}">
<input type="hidden" name="ask_phone" value="{{ 1 if invite.ask_phone else 0 }}">
<input type="hidden" name="ask_organization" value="{{ 1 if invite.ask_organization else 0 }}">
<button type="submit" class="btn btn-sm btn-outline-warning">Отправить повторно</button>
</form>
{% endif %}
<form method="POST" action="{{ url_for('delete_invite', invite_id=invite.id) }}" onsubmit="return confirm('Удалить приглашение?')">
<button type="submit" class="btn btn-sm btn-outline-danger">Удалить</button>
</form>
</div>
</div>
<div class="collapse" id="r{{ invite.id }}">
<div class="card-body">
{% if invite.responded and results[invite.id] %}
{% set result = results[invite.id] %}
{% set scores = result.platform_scores | from_json %}
{% set unsupported = result.unsupported | from_json %}
<p><strong>ФИО:</strong> {{ result.full_name or '—' }}</p>
<p><strong>Телефон:</strong> {{ result.phone or '—' }}</p>
<p><strong>Организация:</strong> {{ result.organization or '—' }}</p>
<p><strong>Получен:</strong> {{ result.submitted_at.strftime('%d.%m.%Y %H:%M') }}</p>
<hr>
<p><strong>Процент соответствия платформ:</strong></p>
<ul>
{% for p, percent in scores.items() %}
<li>{{ p }}: {{ percent }}%</li>
{% endfor %}
</ul>
<p><strong>Неподдерживаемые функции:</strong></p>
<ul>
{% for p, items in unsupported.items() %}
<li>{{ p }}:
{% if items %}
{{ items | join(", ") }}
{% else %}
все поддерживаются
{% endif %}
</li>
{% endfor %}
</ul>
<p><strong>Комментарий:</strong><br>{{ results[invite.id].comment or "—" }}</p>
{% else %}
<p class="text-danger">Ответ ещё не получен.</p>
{% endif %}
</div>
</div>
</div>
{% endfor %}
{% else %}
<p>Вы ещё не отправляли опросы.</p>
{% endif %}
</div>
{% endblock %}