history page works
This commit is contained in:
@@ -79,9 +79,7 @@ impl CardStatistics {
|
||||
self.score = MAX_SCORE
|
||||
}
|
||||
self.last_open = Utc::now();
|
||||
updateCardStat(self.id, self.score, last_open).catch((err) =>
|
||||
console.error('[Training] Ошибка сохранения last_opened:', err),
|
||||
); }
|
||||
}
|
||||
|
||||
pub fn calculated_score(&self) -> f32 {
|
||||
let time = Utc::now() - self.last_open;
|
||||
|
||||
@@ -55,9 +55,7 @@ export function calculatedScore(stat: CardStatistics): number {
|
||||
const now = Date.now();
|
||||
const diffMs = now - stat.last_open;
|
||||
const days = diffMs / (1000 * 60 * 60 * 24);
|
||||
console.log(`Days ${days}`)
|
||||
const multiplier = Math.pow(FADE_PER_DAY, Math.max(0, days));
|
||||
console.log(`multiplier ${multiplier}`)
|
||||
const v = stat.score * multiplier;
|
||||
return v;
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,5 +1,4 @@
|
||||
import { getHistory } from './history.ts';
|
||||
import type { RepetitionRecord } from './history.ts';
|
||||
import { execute } from './sqlite-manager.ts';
|
||||
|
||||
export interface HistoryViewCallbacks {
|
||||
@@ -24,12 +23,15 @@ export async function renderHistoryView(
|
||||
</div>
|
||||
`;
|
||||
|
||||
console.log('[History] Загрузка истории для set_id:', setId);
|
||||
|
||||
document.getElementById('btnHistoryBack')?.addEventListener('click', () => {
|
||||
callbacks.onBack();
|
||||
});
|
||||
|
||||
try {
|
||||
const records = await getHistory(setId, 2000);
|
||||
console.log('[History] Получено записей:', records.length, records);
|
||||
|
||||
// Получаем слова для отображения
|
||||
const wordIds = [...new Set(records.map((r) => r.word_id))];
|
||||
|
||||
+27
@@ -237,6 +237,8 @@ function showSetDetail(set: CardSetRecord, listItem: HTMLLIElement) {
|
||||
</select>
|
||||
|
||||
<button class="btn btn-primary btn-start-training" data-set-id="${set.id}">▶ Начать тренировку</button>
|
||||
|
||||
<button class="btn btn-history" data-set-id="${set.id}" style="width:100%;margin-top:8px;">📊 История повторений</button>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -258,6 +260,24 @@ function showWordView(word: Word) {
|
||||
);
|
||||
}
|
||||
|
||||
// ----- История -----
|
||||
|
||||
async function showHistory(setId: number) {
|
||||
hideNav();
|
||||
currentPage = 'history';
|
||||
|
||||
await renderHistoryView(
|
||||
container,
|
||||
setId,
|
||||
{
|
||||
onBack: () => {
|
||||
showNav();
|
||||
switchPage('sets');
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// ----- Тренировка -----
|
||||
|
||||
async function startTraining(setId: number) {
|
||||
@@ -453,6 +473,13 @@ async function main() {
|
||||
const setId = Number((trainingBtn as HTMLElement).dataset.setId);
|
||||
await startTraining(setId);
|
||||
}
|
||||
|
||||
const historyBtn = target.closest('.btn-history');
|
||||
if (historyBtn) {
|
||||
const setId = Number((historyBtn as HTMLElement).dataset.setId);
|
||||
console.log('[App] История для set_id:', setId);
|
||||
await showHistory(setId);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
|
||||
@@ -417,6 +417,86 @@ body {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* ──── История ──── */
|
||||
|
||||
.history-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
.history-card {
|
||||
flex: 1;
|
||||
background: var(--card-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 16px;
|
||||
padding: 0;
|
||||
box-shadow: var(--shadow);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#history-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.history-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.history-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.history-row-word {
|
||||
flex: 1;
|
||||
font-weight: 600;
|
||||
color: var(--text-h);
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.history-row-mode {
|
||||
font-size: 0.8rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.history-row-scores {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
flex-shrink: 0;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.history-score-before {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.history-score-arrow {
|
||||
color: var(--text);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.history-score-after {
|
||||
color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.history-row-date {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text);
|
||||
opacity: 0.7;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ──── Навигация ──── */
|
||||
|
||||
.app-nav {
|
||||
|
||||
+6
-3
@@ -244,15 +244,18 @@ export class TrainingPage {
|
||||
if (stat) {
|
||||
const scoreAfter = Math.round(calculatedScore(stat) * 10) / 10;
|
||||
const word = this.words[current];
|
||||
console.log('[Training] vote debug:', { stat, word, current, scoreBefore, scoreAfter });
|
||||
if (word) {
|
||||
addRepetition({
|
||||
set_id: stat.set_id,
|
||||
const record = {
|
||||
set_id: Number(stat.set_id),
|
||||
word_id: word.id,
|
||||
timestamp: Date.now(),
|
||||
mode,
|
||||
score_before: scoreBefore,
|
||||
score_after: scoreAfter,
|
||||
}).catch((err) => console.error('[Training] Ошибка сохранения истории:', err));
|
||||
};
|
||||
console.log('[Training] Сохраняем историю:', record);
|
||||
addRepetition(record).catch((err) => console.error('[Training] Ошибка сохранения истории:', err));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user