fix(web): keep bulk checkbox selection across post navigation (openspec change keep-bulk-checkboxes)

- Save/restore checked candidate ids in sessionStorage (vesti_bulk_candidates / vesti_bulk_selected)
- Restore checks after page reload when opening a post via ?selected=N
- Fix selector: checkboxes live outside <form> (form=bulk-form attribute), query input[name=ids] globally
- Openspec: new capability candidates-bulk-selection, change archived
This commit is contained in:
kpa39l
2026-09-17 00:52:51 +00:00
parent 8777a0c4a4
commit c8fe5f7c85
8 changed files with 208 additions and 6 deletions
+35 -4
View File
@@ -131,9 +131,15 @@
<!-- Кнопки действий -->
<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">
<form method="post" action="/posts/{{ selected.id }}/reclassify" class="d-inline-flex gap-1 align-items-center">
{{ hid }}
<button class="btn btn-info" type="submit" title="Прогнать через модель (qwen3:8b): направление, релевантность, интерес, резюме">🤖 Обработать моделью</button>
<select name="manual_direction" class="form-select form-select-sm w-auto" title="Направление: выберите — задастся без модели; «— модель —» = классификация LLM">
<option value="">— модель —</option>
{% for d in directions %}
<option value="{{ d }}" {% if d == selected.direction %}selected{% endif %}>{{ d }}</option>
{% endfor %}
</select>
<button class="btn btn-info" type="submit" title="Прогнать через модель (qwen3:8b): направление, релевантность, интерес, резюме; или установить выбранное направление вручную">🤖 Обработать моделью</button>
</form>
{% endif %}
{% if selected.status != 'published' %}
@@ -221,14 +227,39 @@
{% block scripts %}
<script>
(function(){
var boxes = document.querySelectorAll('#bulk-form input[name="ids"]');
var boxes = document.querySelectorAll('input[name="ids"]');
var badge = document.getElementById('sel-count');
var KEY = 'vesti_bulk_selected';
function selSet(){
var s = new Set();
try { s = new Set(JSON.parse(sessionStorage.getItem(KEY) || '[]')); } catch(e) {}
return s;
}
function saveSet(s){
try { sessionStorage.setItem(KEY, JSON.stringify(Array.from(s))); } catch(e) {}
}
function upd(){
var n = 0;
for (var i = 0; i < boxes.length; i++) if (boxes[i].checked) n++;
badge.textContent = n;
}
for (var i = 0; i < boxes.length; i++) boxes[i].addEventListener('change', upd);
// Восстановить сохранённые отметки (кроме текущего, сервер уже отметил его)
var s = selSet();
for (var i = 0; i < boxes.length; i++){
if (s.has(boxes[i].value)) boxes[i].checked = true;
}
for (var i = 0; i < boxes.length; i++){
boxes[i].addEventListener('change', function(){
var st = selSet();
if (this.checked) st.add(this.value); else st.delete(this.value);
saveSet(st);
upd();
});
}
var form = document.getElementById('bulk-form');
if (form) form.addEventListener('submit', function(){
try { sessionStorage.removeItem(KEY); } catch(e) {}
});
upd();
})();
</script>