feat: 新增打字练习记录与首页记录列表
This commit is contained in:
@@ -3,6 +3,9 @@ var typingItems = [];
|
||||
var typingIndex = 0;
|
||||
var typingStats = { correct: 0, errors: 0 };
|
||||
var typed = '';
|
||||
var typingStartedAt = 0;
|
||||
var typingFinished = false;
|
||||
var typingSession = { mode: '', categoryId: '', categoryName: '', itemCount: 0 };
|
||||
|
||||
var KEY_ROWS = [
|
||||
[
|
||||
@@ -171,6 +174,14 @@ function startTyping() {
|
||||
typingIndex = 0;
|
||||
typingStats = { correct: 0, errors: 0 };
|
||||
typed = '';
|
||||
typingStartedAt = Date.now();
|
||||
typingFinished = false;
|
||||
typingSession = {
|
||||
mode: typingMode,
|
||||
categoryId: category.id,
|
||||
categoryName: category.name,
|
||||
itemCount: typingItems.length
|
||||
};
|
||||
document.getElementById('typing-input').style.display = '';
|
||||
document.getElementById('setup-view').style.display = 'none';
|
||||
document.getElementById('practice-view').style.display = 'block';
|
||||
@@ -228,6 +239,79 @@ function renderTypingAccuracy() {
|
||||
',正确率 ' + (totalKeys ? Math.round(typingStats.correct * 100 / totalKeys) : 100) + '%';
|
||||
}
|
||||
|
||||
function formatTypingDuration(seconds) {
|
||||
if (seconds < 60) return seconds + ' 秒';
|
||||
var minutes = Math.floor(seconds / 60);
|
||||
var rest = seconds % 60;
|
||||
return minutes + ' 分 ' + rest + ' 秒';
|
||||
}
|
||||
|
||||
function formatTypingTime(value) {
|
||||
if (!value) return '';
|
||||
var date = new Date(value);
|
||||
if (isNaN(date.getTime())) return value;
|
||||
return date.toLocaleString('zh-CN', { hour12: false });
|
||||
}
|
||||
|
||||
function renderTypingLogs(rows) {
|
||||
var list = document.getElementById('records-list');
|
||||
if (!list) return;
|
||||
if (!rows || !rows.length) {
|
||||
list.innerHTML = '<div class="records-empty">还没有打字记录</div>';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = rows.map(function(row) {
|
||||
var mode = row.mode === 'phrases' ? '日常口语' : '基础词汇';
|
||||
var category = row.category_name || row.category_id || '未分类';
|
||||
return '<div class="record-item">' +
|
||||
'<div class="record-line">' +
|
||||
'<span class="record-mode">' + escTyping(mode) + '</span>' +
|
||||
'<span class="record-category">' + escTyping(category) + '</span>' +
|
||||
'<span class="record-accuracy">正确率 ' + (row.accuracy || 0) + '%</span>' +
|
||||
'<span class="record-duration">用时 ' + escTyping(formatTypingDuration(row.duration_seconds || 0)) + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="record-meta">' +
|
||||
escTyping(formatTypingTime(row.created_at)) + ' · ' + row.item_count +
|
||||
' 个 · 正确 ' + row.correct_keys + ' · 错误 ' + row.error_keys +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function loadTypingLogs() {
|
||||
var list = document.getElementById('records-list');
|
||||
if (!list) return;
|
||||
list.textContent = '加载中...';
|
||||
apiGetTypingLogs().then(renderTypingLogs).catch(function(err) {
|
||||
list.textContent = err && err.status === 401
|
||||
? '登录后可查看打字记录'
|
||||
: '记录加载失败';
|
||||
});
|
||||
}
|
||||
|
||||
function saveTypingLog(accuracy) {
|
||||
if (!typingStartedAt || typingFinished) return;
|
||||
typingFinished = true;
|
||||
var durationSeconds = Math.max(1, Math.round((Date.now() - typingStartedAt) / 1000));
|
||||
apiSaveTypingLog({
|
||||
mode: typingSession.mode,
|
||||
categoryId: typingSession.categoryId,
|
||||
categoryName: typingSession.categoryName,
|
||||
itemCount: typingSession.itemCount,
|
||||
correctKeys: typingStats.correct,
|
||||
errorKeys: typingStats.errors,
|
||||
accuracy: accuracy,
|
||||
durationSeconds: durationSeconds
|
||||
}).then(loadTypingLogs).catch(function() {});
|
||||
}
|
||||
|
||||
function showSetupView() {
|
||||
document.getElementById('typing-input').style.display = '';
|
||||
document.getElementById('practice-view').style.display = 'none';
|
||||
document.getElementById('setup-view').style.display = 'block';
|
||||
loadTypingLogs();
|
||||
}
|
||||
|
||||
function renderKeyboard(target) {
|
||||
var next = target[typed.length] || '';
|
||||
var press = keyPressForChar(next);
|
||||
@@ -307,6 +391,7 @@ function renderTargetProgress(target) {
|
||||
function renderFinish() {
|
||||
var totalKeys = typingStats.correct + typingStats.errors;
|
||||
var accuracy = totalKeys ? Math.round(typingStats.correct * 100 / totalKeys) : 100;
|
||||
saveTypingLog(accuracy);
|
||||
document.getElementById('target-text').innerHTML = '';
|
||||
document.getElementById('chinese-text').textContent = '';
|
||||
document.getElementById('next-key').textContent = '';
|
||||
@@ -319,9 +404,7 @@ function renderFinish() {
|
||||
'<div class="finish-box"><h2>练习完成</h2><p>完成 ' + typingItems.length +
|
||||
' 个,正确率 ' + accuracy + '%</p><button id="btn-again">再练一次</button></div>';
|
||||
document.getElementById('btn-again').addEventListener('click', function() {
|
||||
document.getElementById('typing-input').style.display = '';
|
||||
document.getElementById('setup-view').style.display = 'block';
|
||||
document.getElementById('practice-view').style.display = 'none';
|
||||
showSetupView();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -337,6 +420,9 @@ document.querySelectorAll('.mode-select button').forEach(function(btn) {
|
||||
|
||||
document.getElementById('btn-start').addEventListener('click', startTyping);
|
||||
document.getElementById('btn-restart').addEventListener('click', startTyping);
|
||||
document.getElementById('btn-choose').addEventListener('click', showSetupView);
|
||||
document.getElementById('btn-refresh-records').addEventListener('click', loadTypingLogs);
|
||||
document.getElementById('typing-input').addEventListener('input', handleTypingInput);
|
||||
|
||||
renderCategories();
|
||||
loadTypingLogs();
|
||||
|
||||
Reference in New Issue
Block a user