point / static /js /catalog.js
eithney
code ref
e74eb63
Raw
History Blame Contribute Delete
7.94 kB
/**
* 书籍目录页面 - 主要逻辑
*/
class BookCatalogApp {
constructor() {
this.books = [];
this.filteredBooks = [];
this.statistics = null;
this.init();
}
async init() {
try {
await this.loadStatistics();
await this.loadBooks();
this.setupEventListeners();
} catch (error) {
console.error('应用初始化失败:', error);
this.showToast('应用初始化失败,请刷新页面重试', 'error');
}
}
setupEventListeners() {
// 搜索功能
const searchInput = document.getElementById('searchInput');
const searchBtn = document.getElementById('searchBtn');
searchBtn.addEventListener('click', () => this.performSearch());
searchInput.addEventListener('input', () => this.performSearch());
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') this.performSearch();
});
}
async loadStatistics() {
try {
const response = await fetch('/api/v2/statistics');
if (!response.ok) {
throw new Error('获取统计信息失败');
}
const result = await response.json();
if (!result.success) {
throw new Error(result.error || '获取统计信息失败');
}
this.statistics = result.statistics;
this.renderStatistics();
} catch (error) {
console.error('加载统计信息失败:', error);
// 统计信息加载失败不影响主要功能,只记录错误
}
}
renderStatistics() {
if (!this.statistics) return;
document.getElementById('totalBooks').textContent = this.statistics.total_books || 0;
document.getElementById('totalPages').textContent = this.statistics.total_pages || 0;
document.getElementById('totalPieces').textContent = this.statistics.total_pieces || 0;
document.getElementById('totalCatalogs').textContent = this.statistics.total_catalogs || 0;
document.getElementById('statistics').style.display = 'grid';
}
async loadBooks() {
const loading = document.getElementById('loading');
const booksGrid = document.getElementById('booksGrid');
const emptyState = document.getElementById('emptyState');
loading.style.display = 'block';
booksGrid.style.display = 'none';
emptyState.style.display = 'none';
try {
const response = await fetch('/api/v2/books');
if (!response.ok) {
throw new Error('获取书籍列表失败');
}
const result = await response.json();
if (!result.success) {
throw new Error(result.error || '获取书籍列表失败');
}
this.books = result.books || [];
this.filteredBooks = [...this.books];
console.log(`加载了 ${this.books.length} 本书籍`);
if (this.books.length === 0) {
loading.style.display = 'none';
emptyState.style.display = 'block';
} else {
this.renderBooks();
}
} catch (error) {
console.error('加载书籍列表失败:', error);
loading.style.display = 'none';
emptyState.style.display = 'block';
this.showToast('加载书籍列表失败: ' + error.message, 'error');
}
}
renderBooks() {
const loading = document.getElementById('loading');
const booksGrid = document.getElementById('booksGrid');
const emptyState = document.getElementById('emptyState');
loading.style.display = 'none';
if (this.filteredBooks.length === 0) {
booksGrid.style.display = 'none';
emptyState.innerHTML = `
<div><i class="fas fa-search"></i></div>
<div>未找到匹配的教材</div>
`;
emptyState.style.display = 'block';
return;
}
booksGrid.style.display = 'grid';
emptyState.style.display = 'none';
booksGrid.innerHTML = '';
this.filteredBooks.forEach(book => {
const bookCard = this.createBookCard(book);
booksGrid.appendChild(bookCard);
});
}
createBookCard(book) {
const card = document.createElement('div');
card.className = 'book-card';
card.dataset.bookId = book.market_book_id;
// 构建封面URL
const coverUrl = this.getCoverUrl(book);
// 年级和学期信息
const gradeInfo = this.getGradeInfo(book.grade_id, book.reel_id);
card.innerHTML = `
<img class="book-cover" src="${coverUrl}" alt="${book.market_book_name}"
onerror="this.style.display='none'">
<div class="book-info">
<div class="book-name" title="${book.market_book_name}">${book.market_book_name}</div>
<div class="book-meta">
<span><i class="fas fa-file-alt"></i> ${book.max_page || 0} 页</span>
<span>${gradeInfo}</span>
</div>
<div class="book-classify">${book.market_classify_name || '未分类'}</div>
</div>
`;
// 点击事件
card.addEventListener('click', () => {
this.openBook(book.market_book_id);
});
return card;
}
getCoverUrl(book) {
if (book.market_book_cover) {
// 如果有封面路径,使用 data 目录
return `data/${book.market_book_cover}`;
}
// 默认封面
return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjI4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9IjI4MCIgZmlsbD0iIzY2N2VlYSIvPjx0ZXh0IHg9IjUwJSIgeT0iNTAlIiBmb250LWZhbWlseT0iQXJpYWwiIGZvbnQtc2l6ZT0iMjQiIGZpbGw9IndoaXRlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkeT0iLjNlbSI+8J+TljwvdGV4dD48L3N2Zz4=';
}
getGradeInfo(gradeId, reelId) {
const grades = {
40: '一年级',
41: '二年级',
42: '三年级',
43: '四年级',
44: '五年级',
45: '六年级'
};
const reels = {
1: '上册',
2: '下册'
};
const grade = grades[gradeId] || `年级${gradeId}`;
const reel = reels[reelId] || `学期${reelId}`;
return `${grade}${reel}`;
}
performSearch() {
const keyword = document.getElementById('searchInput').value.trim().toLowerCase();
if (!keyword) {
this.filteredBooks = [...this.books];
} else {
this.filteredBooks = this.books.filter(book => {
return book.market_book_name.toLowerCase().includes(keyword) ||
(book.market_classify_name && book.market_classify_name.toLowerCase().includes(keyword));
});
}
this.renderBooks();
}
openBook(bookId) {
// 跳转到阅读页面
window.location.href = `/reader?book_id=${bookId}`;
}
showToast(message, type = 'info') {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.className = `toast ${type} show`;
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
}
// 页面加载完成后初始化应用
document.addEventListener('DOMContentLoaded', () => {
new BookCatalogApp();
});