Spaces:
Sleeping
Sleeping
| /** | |
| * 书籍目录页面 - 主要逻辑 | |
| */ | |
| 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(); | |
| }); | |