first commit

This commit is contained in:
2026-05-06 13:28:54 +03:00
commit 79768a4fac
13 changed files with 1827 additions and 0 deletions
+196
View File
@@ -0,0 +1,196 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Отзывы Wildberries</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}" />
</head>
<body>
<div class="page">
<header>
<h1>Отзывы Wildberries</h1>
<p class="hint">Используйте кнопки ниже, чтобы загрузить свежие отзывы или оставить только неотвеченные.</p>
<div class="user-bar">
<span>Вы вошли как {{ current_user["username"] }}</span>
<a href="{{ url_for('logout') }}">Выйти</a>
</div>
</header>
{% if error_message %}
<div class="alert alert-error">{{ error_message }}</div>
{% endif %}
{% if success_message %}
<div class="alert alert-success">{{ success_message }}</div>
{% endif %}
<div class="cabinet-link">
<a href="{{ url_for('cabinet') }}">Личный кабинет</a>
{% if active_token_name %}
<span>Текущий токен: {{ active_token_name }}</span>
{% else %}
<span>Токен не выбран</span>
{% endif %}
</div>
<form class="controls" method="get" action="/">
<div class="star-filter">
<span>Выберите оценки:</span>
{% for star in [5,4,3,2,1] %}
<label>
<input type="checkbox" name="stars" value="{{ star }}" {% if star in selected_stars %}checked{% endif %}>
{{ star }}★
</label>
{% endfor %}
</div>
<div class="control-buttons">
<button type="submit" name="action" value="all">Выгрузить отзывы</button>
<button type="submit" name="action" value="unanswered">Только неотвеченные</button>
<button type="submit" name="action" value="unanswered" class="secondary" formaction="/?stars=5&stars=4">Новые 5★ и 4★</button>
<button type="submit" name="action" value="clear" class="secondary">Очистить список</button>
</div>
</form>
<section class="auto-reply">
<div>
<strong>Автоответ:</strong>
{% if auto_reply_enabled %}
<span class="badge">Включён</span>
{% else %}
<span class="badge badge-inactive">Выключен</span>
{% endif %}
<p>При включении сервис каждые {{ auto_reply_interval_minutes }} минут проверяет новые отзывы 5★ и 4★ и отвечает случайным текстом из пула.</p>
</div>
<form method="post" action="{{ url_for('auto_reply_toggle') }}">
<input type="hidden" name="enabled" value="{{ 0 if auto_reply_enabled else 1 }}">
<button type="submit">{{ "✓ Автоответ включён" if auto_reply_enabled else "Включить автоответ" }}</button>
</form>
</section>
<section class="auto-reply-pools">
<h2>Пулы автоответов</h2>
<p>Один вариант ответа в каждой строке. Для каждого нового отзыва 5★/4★ текст выбирается случайно.</p>
<form method="post" action="{{ url_for('auto_reply_pools') }}">
<label for="pool-5">Ответы для 5★</label>
<textarea id="pool-5" name="pool_5" rows="5" required>{{ reply_pool_5_text }}</textarea>
<label for="pool-4">Ответы для 4★</label>
<textarea id="pool-4" name="pool_4" rows="5" required>{{ reply_pool_4_text }}</textarea>
<button type="submit">Сохранить пулы</button>
</form>
</section>
<section class="auto-reply-logs">
<h2>Журнал автоответов (последние 100)</h2>
{% if auto_reply_logs %}
<div class="logs-table-wrap">
<table class="logs-table">
<thead>
<tr>
<th>Дата</th>
<th>Оценка</th>
<th>Товар</th>
<th>Покупатель</th>
<th>Статус</th>
<th>Ответ</th>
</tr>
</thead>
<tbody>
{% for log in auto_reply_logs %}
<tr>
<td>{{ log["created_at"] }}</td>
<td>{{ log["rating"] }}★</td>
<td>{{ log["product_name"] or "-" }}</td>
<td>{{ log["user_name"] or "-" }}</td>
<td>{{ "Отправлен" if log["status"] == "sent" else "Ошибка" }}</td>
<td>{{ log["reply_text"] }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<p>Пока нет записей автоответа.</p>
{% endif %}
</section>
{% if reviews %}
<section class="summary">
{% if current_filter == 'unanswered' %}
<h2>Неотвеченные отзывы</h2>
{% else %}
<h2>Все отзывы</h2>
{% endif %}
<p>Показано {{ reviews|length }} отзывов. Выбраны оценки: {{ selected_stars_display|join(', ') }}★.</p>
</section>
{% if current_filter == 'unanswered' and has_token %}
<form class="reply-form" method="post" action="{{ url_for('reply_all') }}">
<label for="reply-text">Ответ для всех неотвеченных отзывов</label>
<textarea id="reply-text" name="message" rows="4" placeholder="Напишите ответ один раз — он будет отправлен каждому неотвеченному отзыву" required></textarea>
{% for star in selected_stars_display %}
<input type="hidden" name="stars" value="{{ star }}">
{% endfor %}
{% for review in reviews %}
<input type="hidden" name="review_id" value="{{ review.id }}">
{% endfor %}
<div class="reply-form__actions">
<span>Допустимая длина ответа: 2–5000 символов.</span>
<button type="submit">Ответить всем</button>
</div>
</form>
{% endif %}
<section class="reviews">
{% for review in reviews %}
<article class="review">
<header class="review__header">
<div>
<strong>{{ review.product_name or 'Без названия' }}</strong>
<span class="rating">★ {{ review.rating }}</span>
</div>
<div class="meta">
<span>{{ review.user_name or 'Покупатель' }}</span>
<span>{{ review.created_at|format_datetime }}</span>
</div>
</header>
{% if review.text %}
<p class="review__text">{{ review.text }}</p>
{% endif %}
<dl class="details">
{% if review.pros %}
<dt>Достоинства</dt>
<dd>{{ review.pros }}</dd>
{% endif %}
{% if review.cons %}
<dt>Недостатки</dt>
<dd>{{ review.cons }}</dd>
{% endif %}
</dl>
<footer>
{% if review.answer %}
<p class="answer"><strong>Ответ:</strong> {{ review.answer }}</p>
{% else %}
<p class="no-answer">Без ответа</p>
{% endif %}
</footer>
{% if has_token %}
<details class="inline-reply">
<summary>Ответить</summary>
<form method="post" action="{{ url_for('reply_single', review_id=review.id) }}">
<textarea name="message" rows="3" placeholder="Введите ответ" required></textarea>
{% for star in selected_stars_display %}
<input type="hidden" name="stars" value="{{ star }}">
{% endfor %}
<input type="hidden" name="next_action" value="{{ 'unanswered' if current_filter == 'unanswered' else 'all' }}">
<button type="submit">Отправить</button>
</form>
</details>
{% endif %}
</article>
{% endfor %}
</section>
{% elif current_filter %}
<div class="alert">Отзывы с выбранными оценками ({{ selected_stars_display|join(', ') }}★) не найдены.</div>
{% endif %}
</div>
</body>
</html>