mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 09:55:03 +00:00
selected-layout-stay: отбор остаётся на кандидатах; отобранные — layout на всю высоту (резюме под кнопками, редактор+оригинал в рост, публикация внизу)
This commit is contained in:
+4
-4
@@ -377,13 +377,13 @@ def selected(request: Request, direction: str = "", own: str = "", q: str = "",
|
||||
@app.post("/posts/{post_id}/select")
|
||||
def post_select(post_id: int, request: Request,
|
||||
group_by: str = Form(""), direction: str = Form(""), own: str = Form(""), q: str = Form("")):
|
||||
"""Отобрать кандидата (new → selected). Затем переходим в отобранные."""
|
||||
"""Отобрать кандидата (new → selected). Остаёмся на странице кандидатов."""
|
||||
_require_auth(request)
|
||||
conn = _db()
|
||||
conn.execute("UPDATE posts SET status='selected' WHERE id=? AND status='new' AND is_own=0", (post_id,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, src="selected", selected=post_id), status_code=302)
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, src="candidates"), status_code=302)
|
||||
|
||||
|
||||
@app.post("/candidates/select")
|
||||
@@ -415,11 +415,11 @@ def candidates_bulk(request: Request, action: str = Form(...), ids: list[int] =
|
||||
ph = ", ".join("?" * len(ids))
|
||||
rows = conn.execute(f"SELECT * FROM posts WHERE id IN ({ph})", ids).fetchall()
|
||||
if action == "select":
|
||||
# отбор кандидатов (new → selected)
|
||||
# отбор кандидатов (new → selected); остаёмся на странице кандидатов
|
||||
conn.execute("UPDATE posts SET status='selected' WHERE id IN ({}) AND status='new' AND is_own=0".format(ph), ids)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return RedirectResponse(url=_cand_back(group_by, direction, own, q, src="selected"), status_code=302)
|
||||
return RedirectResponse(url=back, status_code=302)
|
||||
if action == "reject":
|
||||
conn.execute(f"UPDATE posts SET status='rejected' WHERE id IN ({ph})", ids)
|
||||
conn.commit()
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<div class="row g-0">
|
||||
<!-- ЛЕВАЯ ПАНЕЛЬ: список + группировка + массовые операции -->
|
||||
<div class="col-md-4">
|
||||
<div class="border rounded p-2 d-flex flex-column" style="max-height: 82vh; background:#fff;">
|
||||
<div class="border rounded p-2 d-flex flex-column" style="max-height: calc(100vh - 160px); background:#fff;">
|
||||
<div class="d-flex flex-wrap align-items-center mb-1 gap-1">
|
||||
<span class="me-1 text-muted small">Группировка:</span>
|
||||
{% for val, label in [('source', 'источник'), ('date', 'дата'), ('status', 'статус')] %}
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
<!-- ПРАВАЯ ПАНЕЛЬ: детали выбранного -->
|
||||
<div class="col-md-8">
|
||||
<div class="border rounded p-3 bg-white d-flex flex-column" style="height: 82vh;">
|
||||
<div class="border rounded p-3 bg-white d-flex flex-column" style="height: calc(100vh - 160px);">
|
||||
{% if selected %}
|
||||
<div class="d-flex justify-content-between align-items-start flex-shrink-0">
|
||||
<h5 class="mb-0">#{{ selected.id }} {{ selected.source_name or '?' }}</h5>
|
||||
|
||||
+99
-90
@@ -43,7 +43,7 @@
|
||||
<div class="row g-0">
|
||||
<!-- ЛЕВАЯ ПАНЕЛЬ: список отобранных -->
|
||||
<div class="col-md-4">
|
||||
<div class="border rounded p-2 d-flex flex-column" style="max-height: 82vh; background:#fff;">
|
||||
<div class="border rounded p-2 d-flex flex-column" style="max-height: calc(100vh - 160px); background:#fff;">
|
||||
<div class="d-flex flex-wrap align-items-center mb-1 gap-1">
|
||||
<span class="me-1 text-muted small">Группировка:</span>
|
||||
{% for val, label in [('source', 'источник'), ('date', 'дата'), ('status', 'статус')] %}
|
||||
@@ -111,103 +111,112 @@
|
||||
</div>
|
||||
|
||||
<!-- ПРАВАЯ ПАНЕЛЬ: детали отобранного + подготовка своего поста -->
|
||||
<div class="col-md-8">
|
||||
<div class="border rounded p-3 bg-white d-flex flex-column" style="height: 82vh;">
|
||||
{% if selected %}
|
||||
<div class="d-flex justify-content-between align-items-start flex-shrink-0">
|
||||
<h5 class="mb-0">#{{ selected.id }} {{ selected.source_name or '?' }}</h5>
|
||||
<small class="text-muted">{{ (selected.published_at or selected.fetched_at) | dt }}</small>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
{% if selected.direction %}<span class="badge bg-secondary">{{ selected.direction }}</span>{% endif %}
|
||||
{% if selected.relevance %}<span class="badge bg-{{ 'success' if selected.relevance=='critical' else 'info' }}">{{ selected.relevance }}</span>{% endif %}
|
||||
{% if selected.interest %}<span class="badge bg-warning text-dark">interest {{ selected.interest }}</span>{% endif %}
|
||||
{% if selected.is_own %}<span class="badge bg-warning text-dark">⭐ СВОЙ</span>{% endif %}
|
||||
{% if selected.fwd_from_channel_id %}<span class="badge bg-light text-dark">↩︎ форвард</span>{% endif %}
|
||||
<small class="text-muted ms-2">👁 {{ selected.views }} 💬 {{ selected.reactions_total }}</small>
|
||||
{% if selected.url %}<a class="btn btn-sm btn-outline-secondary ms-2" href="{{ selected.url }}" target="_blank">Исходник</a>{% endif %}
|
||||
</div>
|
||||
<div class="mb-3 flex-shrink-0">
|
||||
{% set hid %}<input type="hidden" name="group_by" value="{{ group_by }}"><input type="hidden" name="direction" value="{{ direction }}"><input type="hidden" name="own" value="{{ own }}"><input type="hidden" name="q" value="{{ q }}"><input type="hidden" name="src" value="selected">{% endset %}
|
||||
<div class="d-flex flex-wrap gap-2 mb-2">
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/reclassify">
|
||||
{{ hid }}
|
||||
<button class="btn btn-info" type="submit" title="Прогнать через модель (qwen3:8b): направление, релевантность, интерес, резюме">🤖 Обработать моделью</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/rewrite">
|
||||
{{ hid }}
|
||||
<button class="btn btn-outline-primary" type="submit" title="Сгенерировать черновик своего поста через модель — затем отредактируйте в поле справа">✍️ Переписать</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if selected.status != 'rejected' and selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/reject">
|
||||
{{ hid }}
|
||||
<button class="btn btn-outline-danger" type="submit">🚫 Отклонить</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<div class="col-md-8">
|
||||
<div class="border rounded p-3 bg-white d-flex flex-column" style="height: calc(100vh - 160px);">
|
||||
{% if selected %}
|
||||
<div class="d-flex justify-content-between align-items-start flex-shrink-0">
|
||||
<h5 class="mb-0">#{{ selected.id }} {{ selected.source_name or '?' }}</h5>
|
||||
<small class="text-muted">{{ (selected.published_at or selected.fetched_at) | dt }}</small>
|
||||
</div>
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/approve" id="approve-form">
|
||||
{{ hid }}
|
||||
<label class="form-label small text-muted mb-0 d-block">💬 Мой комментарий (будет первым в канале):</label>
|
||||
<textarea class="form-control form-control-sm mt-1" name="comment" rows="2"
|
||||
placeholder="Комментарий/анонс…">{{ selected.comment or '' }}</textarea>
|
||||
<div class="mt-2 d-flex flex-wrap gap-2">
|
||||
<button class="btn btn-success" type="submit" title="Опубликовать в канал: комментарий (если есть) первым, затем ваш текст (поле справа)/пересказ, картинка, ссылка">✅ Опубликовать</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" type="submit"
|
||||
formaction="/posts/{{ selected.id }}/comment"
|
||||
title="Сохранить комментарий в черновик (не публикует). Он подтянется при следующей публикации">💾 Сохранить комментарий</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- подготовка своего поста: редактор + оригинал рядом -->
|
||||
<hr class="flex-shrink-0">
|
||||
<div class="row g-2 flex-shrink-0">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted">✍️ Мой пост (редактируйте/сохраните — пойдёт в канал от вашего имени)</h6>
|
||||
<form method="post" action="/posts/{{ selected.id }}/rewrite-save" class="row g-1">
|
||||
<div class="mb-2 flex-shrink-0">
|
||||
{% if selected.direction %}<span class="badge bg-secondary">{{ selected.direction }}</span>{% endif %}
|
||||
{% if selected.relevance %}<span class="badge bg-{{ 'success' if selected.relevance=='critical' else 'info' }}{{ 'border' if selected.relevance=='critical' else '' }}">{{ selected.relevance }}</span>{% endif %}
|
||||
{% if selected.interest %}<span class="badge bg-warning text-dark">interest {{ selected.interest }}</span>{% endif %}
|
||||
{% if selected.is_own %}<span class="badge bg-warning text-dark">⭐ СВОЙ</span>{% endif %}
|
||||
{% if selected.fwd_from_channel_id %}<span class="badge bg-light text-dark">↩︎ форвард</span>{% endif %}
|
||||
<small class="text-muted ms-2">👁 {{ selected.views }} 💬 {{ selected.reactions_total }}</small>
|
||||
{% if selected.url %}<a class="btn btn-sm btn-outline-secondary ms-2" href="{{ selected.url }}" target="_blank">Исходник</a>{% endif %}
|
||||
</div>
|
||||
{% set hid %}<input type="hidden" name="group_by" value="{{ group_by }}"><input type="hidden" name="direction" value="{{ direction }}"><input type="hidden" name="own" value="{{ own }}"><input type="hidden" name="q" value="{{ q }}"><input type="hidden" name="src" value="selected">{% endset %}
|
||||
<!-- Кнопки действий -->
|
||||
<div class="d-flex flex-wrap gap-2 mb-2 flex-shrink-0">
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/reclassify">
|
||||
{{ hid }}
|
||||
<textarea class="form-control form-control-sm" name="rewritten_text" rows="8">{{ selected.rewritten_text or '' }}</textarea>
|
||||
<div class="col-auto mt-1">
|
||||
<button class="btn btn-sm btn-outline-primary" type="submit">💾 Сохранить</button>
|
||||
<button class="btn btn-info" type="submit" title="Прогнать через модель (qwen3:8b): направление, релевантность, интерес, резюме">🤖 Обработать моделью</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/rewrite">
|
||||
{{ hid }}
|
||||
<button class="btn btn-outline-primary" type="submit" title="Сгенерировать черновик своего поста через модель — затем отредактируйте в поле справа">✍️ Переписать</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if selected.status != 'rejected' and selected.status != 'published' %}
|
||||
<form method="post" action="/posts/{{ selected.id }}/reject">
|
||||
{{ hid }}
|
||||
<button class="btn btn-outline-danger" type="submit">🚫 Отклонить</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
<!-- Резюме — сразу под кнопками -->
|
||||
{% if selected.summary %}
|
||||
<div class="flex-shrink-0 mb-2">
|
||||
<div class="border rounded bg-light p-2 small">
|
||||
<span class="badge bg-secondary">резюме</span> {{ selected.summary }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr class="flex-shrink-0 my-2">
|
||||
<!-- подготовка своего поста: редактор + оригинал рядом, на всю оставшуюся высоту -->
|
||||
<div class="row g-2 flex-grow-1" style="min-height:0;">
|
||||
<div class="col-md-6 d-flex flex-column" style="min-height:0;">
|
||||
<h6 class="text-muted">✍️ Мой пост (редактируйте/сохраните — пойдёт в канал от вашего имени)</h6>
|
||||
<form method="post" action="/posts/{{ selected.id }}/rewrite-save" class="row g-1 d-flex flex-column flex-grow-1" style="min-height:0;">
|
||||
{{ hid }}
|
||||
<textarea class="form-control form-control-sm flex-grow-1" name="rewritten_text" rows="8" style="flex-grow:1; min-height:140px; resize:vertical;">{{ selected.rewritten_text or '' }}</textarea>
|
||||
<div class="col-auto mt-1">
|
||||
<button class="btn btn-sm btn-outline-primary" type="submit">💾 Сохранить</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 d-flex flex-column" style="min-height:0;">
|
||||
<h6 class="text-muted">Оригинальный пост</h6>
|
||||
<div class="border rounded p-2 bg-light small overflow-auto flex-grow-1" style="min-height:0;">
|
||||
{% if selected.text %}
|
||||
<div class="post-text">{{ selected.text | markdown }}</div>
|
||||
{% endif %}
|
||||
{% if selected.media_path %}
|
||||
{% set media_src = '/media/' ~ selected.media_path.split('/')[-1] %}
|
||||
{% set media_ext = selected.media_path.lower().rsplit('.', 1)[-1] if '.' in selected.media_path else '' %}
|
||||
{% if media_ext in ['jpg','jpeg','png','gif','webp'] %}
|
||||
<a href="{{ media_src }}" target="_blank" title="Открыть полноразмер">
|
||||
<img src="{{ media_src }}" class="img-fluid rounded mt-2 d-block" style="max-height:50vh" alt="медиа поста">
|
||||
</a>
|
||||
{% elif media_ext in ['mp4','webm','mov'] %}
|
||||
<video src="{{ media_src }}" controls class="mt-2 d-block" style="max-height:50vh"></video>
|
||||
{% else %}
|
||||
<a class="btn btn-sm btn-outline-secondary mt-2" href="{{ media_src }}" target="_blank">📎 Медиафайл</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="flex-shrink-0 my-2">
|
||||
<!-- Комментарий + публикация — в самом низу -->
|
||||
{% if selected.status != 'published' %}
|
||||
<div class="flex-shrink-0 pt-2 border-top">
|
||||
<form method="post" action="/posts/{{ selected.id }}/approve" id="approve-form">
|
||||
{{ hid }}
|
||||
<label class="form-label small text-muted mb-0 d-block">💬 Мой комментарий (будет первым в канале):</label>
|
||||
<textarea class="form-control form-control-sm mt-1" name="comment" rows="2"
|
||||
placeholder="Комментарий/анонс…">{{ selected.comment or '' }}</textarea>
|
||||
<div class="mt-2 d-flex flex-wrap gap-2">
|
||||
<button class="btn btn-success" type="submit" title="Опубликовать в канал: комментарий (если есть) первым, затем ваш текст (поле справа)/пересказ, картинка, ссылка">✅ Опубликовать</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" type="submit"
|
||||
formaction="/posts/{{ selected.id }}/comment"
|
||||
title="Сохранить комментарий в черновик (не публикует). Он подтянется при следующей публикации">💾 Сохранить комментарий</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted">Оригинальный пост</h6>
|
||||
<div class="border rounded p-2 bg-light small overflow-auto" style="max-height:300px;">
|
||||
{% if selected.text %}
|
||||
<div class="post-text">{{ selected.text | markdown }}</div>
|
||||
{% endif %}
|
||||
{% if selected.media_path %}
|
||||
{% set media_src = '/media/' ~ selected.media_path.split('/')[-1] %}
|
||||
{% set media_ext = selected.media_path.lower().rsplit('.', 1)[-1] if '.' in selected.media_path else '' %}
|
||||
{% if media_ext in ['jpg','jpeg','png','gif','webp'] %}
|
||||
<a href="{{ media_src }}" target="_blank" title="Открыть полноразмер">
|
||||
<img src="{{ media_src }}" class="img-fluid rounded mt-2 d-block" style="max-height:320px" alt="медиа поста">
|
||||
</a>
|
||||
{% elif media_ext in ['mp4','webm','mov'] %}
|
||||
<video src="{{ media_src }}" controls class="mt-2 d-block" style="max-height:320px"></video>
|
||||
{% else %}
|
||||
<a class="btn btn-sm btn-outline-secondary mt-2" href="{{ media_src }}" target="_blank">📎 Медиафайл</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if selected.summary %}<div class="mt-2"><span class="badge bg-light text-dark">резюме</span> {{ selected.summary }}</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<div class="alert alert-info py-3">Выберите отобранный пост слева</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="alert alert-info py-3">Выберите отобранный пост слева</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
<script>
|
||||
|
||||
Reference in New Issue
Block a user