first commit
This commit is contained in:
@@ -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>
|
||||
Reference in New Issue
Block a user