244 lines
8.3 KiB
JavaScript
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();
|
|
});
|