Filtering bad

This commit is contained in:
2026-07-05 13:34:23 +03:00
parent c184945e95
commit 064c39924b
3 changed files with 119 additions and 52 deletions
+1 -1
View File
@@ -23,4 +23,4 @@ dist-ssr
*.sln *.sln
*.sw? *.sw?
jwl.tar.gz jwl.tar.gz
/.jwl /jwl
+67 -19
View File
@@ -5,6 +5,11 @@ export interface HistoryViewCallbacks {
onBack: () => void; onBack: () => void;
} }
let allRecords: any[] = [];
let showBadOnly = false;
const BAD_MODES = new Set(['hard', 'none']);
/** /**
* Показывает страницу истории повторений для указанной колоды. * Показывает страницу истории повторений для указанной колоды.
*/ */
@@ -13,46 +18,97 @@ export async function renderHistoryView(
setId: number, setId: number,
callbacks: HistoryViewCallbacks, callbacks: HistoryViewCallbacks,
): Promise<void> { ): Promise<void> {
showBadOnly = false;
container.innerHTML = ` container.innerHTML = `
<div class="history-header"> <div class="history-header">
<button id="btnHistoryBack" class="btn" style="flex:none; padding:0.4rem 0.8rem;">← Назад</button> <button id="btnHistoryBack" class="btn" style="flex:none; padding:0.4rem 0.8rem;">← Назад</button>
<span style="font-size:0.85rem;color:var(--text);">Загрузка...</span> <span style="font-size:0.85rem;color:var(--text);">Загрузка...</span>
</div> </div>
<div class="history-filters">
<button id="btnFilterAll" class="btn btn-filter active">📊 Все записи</button>
<button id="btnFilterBad" class="btn btn-filter">🔴 Только плохие</button>
</div>
<div class="history-card"> <div class="history-card">
<div id="history-content" style="text-align:center;padding:2rem;opacity:0.6;">Загрузка истории...</div> <div id="history-content" style="text-align:center;padding:2rem;opacity:0.6;">Загрузка истории...</div>
</div> </div>
`; `;
console.log('[History] Загрузка истории для set_id:', setId);
document.getElementById('btnHistoryBack')?.addEventListener('click', () => { document.getElementById('btnHistoryBack')?.addEventListener('click', () => {
callbacks.onBack(); callbacks.onBack();
}); });
try { document.getElementById('btnFilterAll')?.addEventListener('click', () => {
const records = await getHistory(setId, 2000); showBadOnly = false;
console.log('[History] Получено записей:', records.length, records); updateFilterButtons();
renderRows(container);
});
// Получаем слова для отображения document.getElementById('btnFilterBad')?.addEventListener('click', () => {
const wordIds = [...new Set(records.map((r) => r.word_id))]; showBadOnly = true;
updateFilterButtons();
renderRows(container);
});
try {
allRecords = await getHistory(setId, 2000);
const wordIds = [...new Set(allRecords.map((r) => r.word_id))];
const wordMap = await getWordMap(wordIds); const wordMap = await getWordMap(wordIds);
// Сохраняем wordMap для renderRows
(window as any).__wordMap = wordMap;
const headerSpan = container.querySelector('.history-header span'); const headerSpan = container.querySelector('.history-header span');
if (headerSpan) { if (headerSpan) {
headerSpan.textContent = `записей: ${records.length}`; headerSpan.textContent = `всего записей: ${allRecords.length}`;
} }
renderRows(container);
} catch (err) {
console.error('[History] Ошибка загрузки:', err);
const contentEl = document.getElementById('history-content');
if (contentEl) {
contentEl.innerHTML = '<div style="text-align:center;padding:2rem;color:var(--error);">Ошибка загрузки истории</div>';
}
}
}
function updateFilterButtons() {
const btnAll = document.getElementById('btnFilterAll');
const btnBad = document.getElementById('btnFilterBad');
if (btnAll && btnBad) {
btnAll.classList.toggle('active', !showBadOnly);
btnBad.classList.toggle('active', showBadOnly);
}
}
function renderRows(container: HTMLElement) {
const contentEl = document.getElementById('history-content'); const contentEl = document.getElementById('history-content');
if (!contentEl) return; if (!contentEl) return;
if (records.length === 0) { const wordMap = (window as any).__wordMap as Map<number, string> || new Map();
contentEl.innerHTML = '<div style="text-align:center;padding:2rem;opacity:0.6;">История пуста</div>'; const headerSpan = container.querySelector('.history-header span');
let filtered = allRecords;
if (showBadOnly) {
filtered = allRecords.filter((r) => BAD_MODES.has(r.mode));
}
if (headerSpan) {
headerSpan.textContent = showBadOnly
? `плохих: ${filtered.length} / ${allRecords.length}`
: `всего записей: ${allRecords.length}`;
}
if (filtered.length === 0) {
contentEl.innerHTML = '<div style="text-align:center;padding:2rem;opacity:0.6;">Нет записей</div>';
return; return;
} }
contentEl.innerHTML = ''; contentEl.innerHTML = '';
for (const record of records) { for (const record of filtered) {
const word = wordMap.get(record.word_id); const word = wordMap.get(record.word_id);
const wordText = word ? word : `#${record.word_id}`; const wordText = word ? word : `#${record.word_id}`;
const date = new Date(record.timestamp); const date = new Date(record.timestamp);
@@ -84,13 +140,6 @@ export async function renderHistoryView(
`; `;
contentEl.appendChild(row); contentEl.appendChild(row);
} }
} catch (err) {
console.error('[History] Ошибка загрузки:', err);
const contentEl = document.getElementById('history-content');
if (contentEl) {
contentEl.innerHTML = '<div style="text-align:center;padding:2rem;color:var(--error);">Ошибка загрузки истории</div>';
}
}
} }
async function getWordMap(wordIds: number[]): Promise<Map<number, string>> { async function getWordMap(wordIds: number[]): Promise<Map<number, string>> {
@@ -104,7 +153,6 @@ async function getWordMap(wordIds: number[]): Promise<Map<number, string>> {
wordIds, wordIds,
); );
for (const row of rows) { for (const row of rows) {
// rows — массив массивов [id, key]
map.set(row[0], row[1]); map.set(row[0], row[1]);
} }
} catch { } catch {
+19
View File
@@ -426,6 +426,25 @@ body {
padding: 0.5rem 0; padding: 0.5rem 0;
} }
.history-filters {
display: flex;
gap: 0.5rem;
padding: 0.25rem 0;
}
.btn-filter {
flex: 1;
font-size: 0.8rem;
padding: 0.5rem 0.75rem;
min-height: 40px;
}
.btn-filter.active {
background: var(--accent-light);
border-color: var(--accent);
color: var(--accent);
}
.history-card { .history-card {
flex: 1; flex: 1;
background: var(--card-bg); background: var(--card-bg);