Filtering bad
This commit is contained in:
+1
-1
@@ -23,4 +23,4 @@ dist-ssr
|
|||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
jwl.tar.gz
|
jwl.tar.gz
|
||||||
/.jwl
|
/jwl
|
||||||
+67
-19
@@ -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 {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user