Files
spanish-diary/wordbook.js
T

244 lines
8.3 KiB
JavaScript

var wbBackend = false;
var wbItems = [];
var wbEditId = null;
var LOCAL_WB_KEY = 'spanish_diary_wordbook';
function wbEsc(s) {
var div = document.createElement('div');
div.textContent = s == null ? '' : String(s);
return div.innerHTML;
}
function wbMsg(text) {
document.getElementById('wb-msg').textContent = text || '';
}
function loadLocalWords() {
try {
wbItems = JSON.parse(localStorage.getItem(LOCAL_WB_KEY) || '[]');
} catch (e) {
wbItems = [];
}
renderWordbook();
}
function saveLocalWords() {
localStorage.setItem(LOCAL_WB_KEY, JSON.stringify(wbItems));
}
function loadWords() {
if (wbBackend) {
apiGetVocabulary().then(function(items) {
wbItems = items || [];
renderWordbook();
}).catch(function(err) {
wbMsg(err.message || '加载单词本失败');
});
} else {
loadLocalWords();
}
}
function getFilteredWords() {
var keyword = document.getElementById('search-word').value.trim().toLowerCase();
var category = document.getElementById('filter-category').value;
var sort = document.getElementById('sort-word').value;
var filtered = wbItems.filter(function(item) {
var matchKeyword = !keyword ||
String(item.word || '').toLowerCase().indexOf(keyword) >= 0 ||
String(item.english || '').toLowerCase().indexOf(keyword) >= 0 ||
String(item.chinese || '').toLowerCase().indexOf(keyword) >= 0;
var matchCategory = !category || String(item.category || '') === category;
return matchKeyword && matchCategory;
});
filtered.sort(function(a, b) {
if (sort === 'word') return String(a.word || '').localeCompare(String(b.word || ''), 'es');
if (sort === 'category') {
var c = String(a.category || '').localeCompare(String(b.category || ''), 'zh-CN');
if (c !== 0) return c;
return String(a.word || '').localeCompare(String(b.word || ''), 'es');
}
return String(b.created_at || '').localeCompare(String(a.created_at || ''));
});
return filtered;
}
function renderWordbook() {
var categories = {};
wbItems.forEach(function(item) {
var cat = String(item.category || '其他').trim() || '其他';
categories[cat] = (categories[cat] || 0) + 1;
});
var filter = document.getElementById('filter-category');
var current = filter.value;
var categoryKeys = Object.keys(categories).sort(function(a, b) {
return a.localeCompare(b, 'zh-CN');
});
filter.innerHTML = '<option value="">全部分类</option>' + categoryKeys.map(function(cat) {
return '<option value="' + wbEsc(cat) + '"' + (cat === current ? ' selected' : '') + '>' +
wbEsc(cat) + ' (' + categories[cat] + ')</option>';
}).join('');
document.getElementById('wb-total').textContent = '共 ' + wbItems.length + ' 个单词';
document.getElementById('wb-category-count').textContent = categoryKeys.length + ' 个分类';
var filtered = getFilteredWords();
var container = document.getElementById('wb-list');
if (filtered.length === 0) {
container.innerHTML = '<div class="empty-state">还没有收藏单词,或没有匹配结果</div>';
return;
}
container.innerHTML = filtered.map(function(item) {
var cat = String(item.category || '其他').trim() || '其他';
return '<div class="word-card" data-id="' + item.id + '">' +
'<div class="word-main">' +
'<span class="word-text">' + wbEsc(item.word) + '</span>' +
'<span class="word-cat">' + wbEsc(cat) + '</span>' +
'</div>' +
'<div class="word-langs">' +
'<div class="lang-line"><span class="lang-label">ES</span><span class="lang-value">' + wbEsc(item.word) + '</span><button class="speak-word" data-lang="es">🔊</button></div>' +
'<div class="lang-line"><span class="lang-label">EN</span><span class="lang-value">' + wbEsc(item.english || '-') + '</span><button class="speak-word" data-lang="en">🔊</button></div>' +
'<div class="lang-line"><span class="lang-label">CN</span><span class="lang-value">' + wbEsc(item.chinese || '-') + '</span><button class="speak-word" data-lang="zh">🔊</button></div>' +
'</div>' +
'<div class="word-actions">' +
'<button class="edit-word">编辑</button>' +
'<button class="danger delete-word">删除</button>' +
'</div>' +
'</div>';
}).join('');
}
function addWord() {
var data = {
word: document.getElementById('add-word').value.trim(),
english: document.getElementById('add-english').value.trim(),
chinese: document.getElementById('add-chinese').value.trim(),
category: document.getElementById('add-category').value.trim()
};
if (!data.word) {
wbMsg('请输入西语单词');
return;
}
var finish = function() {
document.getElementById('add-word').value = '';
document.getElementById('add-english').value = '';
document.getElementById('add-chinese').value = '';
document.getElementById('add-category').value = '';
loadWords();
};
if (wbBackend) {
apiAddVocabulary(data).then(finish).catch(function(err) {
wbMsg(err.message || '添加失败');
});
} else {
data.id = 'local-' + Date.now();
data.created_at = new Date().toISOString();
wbItems.unshift(data);
saveLocalWords();
finish();
}
}
function openEdit(id) {
var item = wbItems.find(function(w) { return String(w.id) === String(id); });
if (!item) return;
wbEditId = id;
document.getElementById('edit-word').value = item.word || '';
document.getElementById('edit-english').value = item.english || '';
document.getElementById('edit-chinese').value = item.chinese || '';
document.getElementById('edit-category').value = item.category || '';
document.getElementById('edit-overlay').classList.add('show');
}
function closeEdit() {
wbEditId = null;
document.getElementById('edit-overlay').classList.remove('show');
}
function saveEdit() {
if (!wbEditId) return;
var data = {
word: document.getElementById('edit-word').value.trim(),
english: document.getElementById('edit-english').value.trim(),
chinese: document.getElementById('edit-chinese').value.trim(),
category: document.getElementById('edit-category').value.trim()
};
if (!data.word) {
wbMsg('请输入西语单词');
return;
}
var finish = function() {
closeEdit();
loadWords();
};
if (wbBackend) {
apiUpdateVocabulary(wbEditId, data).then(finish).catch(function(err) {
wbMsg(err.message || '保存失败');
});
} else {
var idx = wbItems.findIndex(function(w) { return String(w.id) === String(wbEditId); });
if (idx >= 0) {
Object.assign(wbItems[idx], data);
saveLocalWords();
}
finish();
}
}
function deleteWord(id) {
if (!confirm('确定从单词本中删除该单词吗?')) return;
var finish = function() {
loadWords();
};
if (wbBackend) {
apiDeleteVocabulary(id).then(finish).catch(function(err) {
wbMsg(err.message || '删除失败');
});
} else {
wbItems = wbItems.filter(function(w) { return String(w.id) !== String(id); });
saveLocalWords();
finish();
}
}
document.getElementById('btn-add-word').addEventListener('click', addWord);
document.getElementById('search-word').addEventListener('input', renderWordbook);
document.getElementById('filter-category').addEventListener('change', renderWordbook);
document.getElementById('sort-word').addEventListener('change', renderWordbook);
document.getElementById('edit-cancel').addEventListener('click', closeEdit);
document.getElementById('edit-save').addEventListener('click', saveEdit);
document.getElementById('wb-list').addEventListener('click', function(e) {
var card = e.target.closest('.word-card');
if (!card) return;
var id = card.dataset.id;
if (e.target.closest('.speak-word')) {
var item = wbItems.find(function(w) { return String(w.id) === String(id); });
if (!item) return;
var lang = e.target.closest('.speak-word').dataset.lang;
if (lang === 'es') speakText(item.word, 'es');
else if (lang === 'en') speakText(item.english, 'en');
else speakText(item.chinese, 'zh');
return;
}
if (e.target.closest('.edit-word')) {
openEdit(id);
return;
}
if (e.target.closest('.delete-word')) {
deleteWord(id);
}
});
apiGetMe().then(function() {
wbBackend = true;
loadWords();
}).catch(function(err) {
if (err && err.status === 401) {
location.href = 'login.html';
return;
}
wbBackend = false;
loadWords();
});