// 全局变量 let allAlbums = []; // 存储所有相册数据 let displayedAlbums = []; // 当前显示的相册数据 let searchTimeout = null; let currentDisplayPage = 1; // 前端显示的分页 let albumsPerPage = 50; // 每次显示50个相册 let isLoadingMore = false; let hasMoreAlbums = true; let lazyLoadObserver = null; let isAllAlbumsLoaded = false; // 标记是否已加载所有相册数据 let isInFavoritesPage = false; // 标记当前是否在收藏页 // 标签和人物筛选 let currentFilter = null; // { type: 'tag'|'person', value: string } let collapsedSections = { people: false, tags: false }; // API基础URL const API_BASE = '/api'; // 图片加载器类 class ImageLoader { constructor() { this.cache = new Map(); } // 加载图片 async loadImage(imageId, element) { // 检查缓存 if (this.cache.has(imageId)) { const cachedData = this.cache.get(imageId); this.setImageSrc(element, cachedData.blobUrl, cachedData.mimeType); return; } try { const response = await fetch(`${API_BASE}/image/${imageId}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const contentType = response.headers.get('content-type'); const imageData = await response.blob(); // 创建Blob URL const mimeType = contentType || 'image/jpeg'; const blob = new Blob([imageData], { type: mimeType }); const blobUrl = URL.createObjectURL(blob); // 缓存结果 this.cache.set(imageId, { blobUrl, mimeType }); // 设置图片源 this.setImageSrc(element, blobUrl, mimeType); } catch (error) { console.error('图片加载失败:', error); // 加载失败时使用占位图 element.src = '/assets/placeholder.svg'; } } // 设置图片源 setImageSrc(element, blobUrl, mimeType) { // 创建新的Image对象进行预加载 const img = new Image(); img.onload = () => { element.src = blobUrl; element.classList.add('loaded'); }; img.onerror = () => { console.error('图片解码失败'); element.src = '/assets/placeholder.svg'; }; img.src = blobUrl; } // 清理缓存 clearCache() { // 清理所有Blob URL for (const [imageId, cached] of this.cache.entries()) { URL.revokeObjectURL(cached.blobUrl); } this.cache.clear(); } } // 创建全局图片加载器实例 const imageLoader = new ImageLoader(); // 设备检测 const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0; // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', function () { // 添加设备类到body if (isMobile) { document.body.classList.add('mobile-device'); } if (isTouchDevice) { document.body.classList.add('touch-device'); } initSearch(); initInfiniteScroll(); initLazyLoading(); // 初始化图片懒加载 // 检查URL中是否有search参数 const urlParams = new URLSearchParams(window.location.search); const searchQuery = urlParams.get('search'); if (searchQuery) { const searchInput = document.getElementById('search-input'); searchInput.value = searchQuery; // 直接搜索,不先加载全部相册 searchAlbums(); } else { loadAlbums(); } }); // 初始化搜索功能 function initSearch() { const searchInput = document.getElementById('search-input'); // 防抖搜索 searchInput.addEventListener('input', function () { clearTimeout(searchTimeout); // 优化:根据输入长度动态调整延迟 const inputLength = this.value.length; const debounceDelay = inputLength > 3 ? 200 : 500; // 长文本快速搜索,短文本慢速搜索 searchTimeout = setTimeout(debouncedSearch, debounceDelay); }); // 移动端优化:搜索框聚焦时自动滚动到可视区域 if (isMobile) { searchInput.addEventListener('focus', function () { setTimeout(() => { searchInput.scrollIntoView({behavior: 'smooth', block: 'center'}); }, 100); }); } } // 初始化无限滚动 function initInfiniteScroll() { let scrollTimeout; window.addEventListener('scroll', function () { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(handleScroll, 100); }); } // 初始化图片懒加载 function initLazyLoading() { // 使用Intersection Observer实现懒加载 if ('IntersectionObserver' in window) { if (lazyLoadObserver) { lazyLoadObserver.disconnect(); } lazyLoadObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; const imageId = img.getAttribute('data-image-id'); if (imageId && !img.classList.contains('loaded')) { imageLoader.loadImage(imageId, img); } lazyLoadObserver.unobserve(img); } }); }, { rootMargin: '100px 0px', // 提前100px开始加载 threshold: 0.1 }); // 观察所有带有data-image-id的图片 document.querySelectorAll('img[data-image-id]').forEach(img => { if (!img.classList.contains('loaded')) { lazyLoadObserver.observe(img); } }); } else { // 不支持Intersection Observer的回退方案 console.warn('浏览器不支持Intersection Observer,使用回退懒加载方案'); initFallbackLazyLoading(); } } // 回退懒加载方案 function initFallbackLazyLoading() { let scrollTimeout; function checkImagesInView() { const images = document.querySelectorAll('img[data-image-id]:not(.loaded)'); const viewportHeight = window.innerHeight; const scrollTop = window.scrollY; images.forEach(img => { const rect = img.getBoundingClientRect(); const isInView = rect.top < viewportHeight + 200 && rect.bottom > -200; if (isInView) { const imageId = img.getAttribute('data-image-id'); if (imageId) { imageLoader.loadImage(imageId, img); } } }); } window.addEventListener('scroll', () => { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(checkImagesInView, 100); }); // 初始检查 checkImagesInView(); } // 处理滚动事件 function handleScroll() { // 如果在收藏页,禁用无限滚动 if (isInFavoritesPage) return; if (isLoadingMore || !hasMoreAlbums) return; // 检查是否滚动到底部 const scrollTop = window.scrollY || document.documentElement.scrollTop; const scrollHeight = document.documentElement.scrollHeight; const clientHeight = window.innerHeight; // 当距离底部还有200px时开始加载 if (scrollTop + clientHeight >= scrollHeight - 200) { loadMoreAlbums(); } } // 加载更多相册(从前端已加载的数据中获取) async function loadMoreAlbums() { // 如果在收藏页,不加载更多数据 if (isInFavoritesPage) return; if (isLoadingMore || !hasMoreAlbums || !isAllAlbumsLoaded) return; isLoadingMore = true; try { // 显示加载更多指示器 showLoadingMore(); // 增加当前显示页数 currentDisplayPage++; // 显示下一页数据 displayCurrentPage(); // 初始化图片懒加载 initLazyLoading(); // 预加载下一批图片 preloadNextBatchImages(); } catch (error) { console.error('加载更多相册失败:', error); showLoadMoreError(); } finally { isLoadingMore = false; hideLoadingMore(); } } // 显示加载更多错误 function showLoadMoreError() { const container = document.getElementById('albums-container'); const errorElement = document.createElement('div'); errorElement.className = 'load-more-error'; errorElement.innerHTML = `
加载失败,点击重试
`; const existingError = container.querySelector('.load-more-error'); if (existingError) { existingError.remove(); } container.appendChild(errorElement); } // 显示骨架屏 function showSkeleton(count = 6) { const container = document.getElementById('albums-container'); container.innerHTML = Array(count).fill(0).map(() => `
`).join(''); } // 显示详细加载状态 function showLoadingState(message = '加载中...', progress = 0) { const container = document.getElementById('albums-container'); const progressWidth = Math.min(Math.max(progress, 0), 100); container.innerHTML = `

${message}

`; } // 显示加载更多指示器 function showLoadingMore() { const container = document.getElementById('albums-container'); const loadingIndicator = document.createElement('div'); loadingIndicator.id = 'loading-more'; loadingIndicator.className = 'loading-more'; loadingIndicator.innerHTML = `
加载更多相册...
`; container.appendChild(loadingIndicator); } // 隐藏加载更多指示器 function hideLoadingMore() { const loadingIndicator = document.getElementById('loading-more'); if (loadingIndicator) { loadingIndicator.remove(); } } // 追加相册到列表 function appendAlbums(albums) { const container = document.getElementById('albums-container'); const newAlbumsHTML = albums.map(album => { // 处理封面图片URL - 使用懒加载 let coverImageUrl = '/assets/placeholder.svg'; let dataSrc = ''; if (album.cover_image_id) { dataSrc = `/api/image/${album.cover_image_id}`; coverImageUrl = '/assets/placeholder.svg'; // 初始使用占位图 } // 格式化日期 const createdDate = new Date(album.created_at).toLocaleDateString('zh-CN'); return `
${album.title}

${album.title}

${album.image_count} 张图片 ${createdDate}
`; }).join(''); // 移除加载指示器并添加新相册 hideLoadingMore(); container.insertAdjacentHTML('beforeend', newAlbumsHTML); // 重新初始化懒加载,观察新添加的图片 initLazyLoading(); } // 加载所有相册数据(一次性加载全部) async function loadAlbums(reset = false) { try { if (reset) { currentDisplayPage = 1; allAlbums = []; displayedAlbums = []; hasMoreAlbums = true; isAllAlbumsLoaded = false; const container = document.getElementById('albums-container'); container.innerHTML = ''; } // 如果已经加载过所有数据,直接显示当前页 if (isAllAlbumsLoaded) { displayCurrentPage(); return; } // 显示骨架屏 showSkeleton(); // 一次性加载所有相册数据 const response = await fetch(`${API_BASE}/albums`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } allAlbums = await response.json(); isAllAlbumsLoaded = true; // 显示第一页数据 displayCurrentPage(); updateStats(allAlbums); // 初始化图片懒加载 initLazyLoading(); // 预加载下一批图片 preloadNextBatchImages(); // 加载热门标签和人物 loadDiscoverData(); } catch (error) { console.error('加载相册失败:', error); showError('加载相册数据失败,请刷新页面重试'); } } // 显示当前页的相册数据 function displayCurrentPage() { const startIndex = (currentDisplayPage - 1) * albumsPerPage; const endIndex = startIndex + albumsPerPage; // 获取当前页要显示的相册 displayedAlbums = allAlbums.slice(startIndex, endIndex); // 如果是第一页,直接显示;否则追加显示 if (currentDisplayPage === 1) { displayAlbums(displayedAlbums); } else { appendAlbums(displayedAlbums); } // 检查是否还有更多数据可以显示 hasMoreAlbums = (currentDisplayPage * albumsPerPage) < allAlbums.length; } // 搜索相册 // 防抖搜索函数 async function debouncedSearch() { const searchTerm = document.getElementById('search-input').value.toLowerCase().trim(); if (searchTerm === '') { // 显示所有已加载的相册 displayAlbums(allAlbums); updateStats(); return; } // 直接使用后端搜索API进行全站搜索 await performServerSearch(searchTerm); } // 在当前已加载的数据集中搜索 function searchInLoadedAlbums(searchTerm) { if (!allAlbums.length) return []; return allAlbums.filter(album => { // 搜索标题和描述 const titleMatch = album.title.toLowerCase().includes(searchTerm); const descriptionMatch = album.description && album.description.toLowerCase().includes(searchTerm); return titleMatch || descriptionMatch; }); } // 显示搜索提示 function showSearchHint(searchTerm) { const container = document.getElementById('albums-container'); container.innerHTML = `

未在当前页面找到 "${searchTerm}"

尝试:

`; document.getElementById('stats').innerHTML = `在当前页面中未找到包含 "${searchTerm}" 的相册`; } // 执行服务器端搜索(全站搜索) async function performServerSearch(searchTerm) { try { // 显示搜索中的骨架屏 showSkeleton(4); const response = await fetch(`${API_BASE}/search?q=${encodeURIComponent(searchTerm)}&page=1&limit=${albumsPerPage}`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const serverResults = await response.json(); if (serverResults.length === 0) { showError(`没有找到包含 "${searchTerm}" 的相册`); return; } // 显示服务器搜索结果 displayAlbums(serverResults); document.getElementById('stats').innerHTML = `在全站找到 ${serverResults.length} 个包含 "${searchTerm}" 的相册`; // 初始化图片懒加载 initLazyLoading(); } catch (error) { console.error('全站搜索失败:', error); showError('全站搜索失败,请重试'); } } // 显示相册列表 function displayAlbums(albums) { const container = document.getElementById('albums-container'); if (albums.length === 0) { container.innerHTML = '

没有找到匹配的相册
'; return; } container.innerHTML = albums.map(album => { // 处理封面图片URL - 使用懒加载 let coverImageUrl = '/assets/placeholder.svg'; let dataSrc = ''; if (album.cover_image_id) { dataSrc = `/api/image/${album.cover_image_id}`; coverImageUrl = '/assets/placeholder.svg'; // 初始使用占位图 } // 格式化日期 const createdDate = new Date(album.created_at).toLocaleDateString('zh-CN'); return `
${album.title}

${album.title}

${album.image_count} 张图片 ${createdDate}
`; }).join(''); } // 预加载下一批图片 function preloadNextBatchImages() { const imagesToPreload = []; const visibleImages = document.querySelectorAll('img[data-image-id]:not(.loaded)'); // 预加载前5张可见图片 visibleImages.forEach((img, index) => { if (index < 5) { const imageId = img.getAttribute('data-image-id'); if (imageId) { imagesToPreload.push(imageId); } } }); // 使用图片加载器预加载 imagesToPreload.forEach(imageId => { const tempImg = new Image(); imageLoader.loadImage(imageId, tempImg); }); } // 更新统计信息 function updateStats(albums) { if (!albums) { albums = allAlbums; } const totalImages = albums.reduce((sum, album) => sum + album.image_count, 0); document.getElementById('stats').innerHTML = `共发现 ${albums.length} 个相册,包含 ${totalImages} 张图片`; } // 显示错误信息 function showError(message) { const container = document.getElementById('albums-container'); container.innerHTML = `

${message}
`; document.getElementById('stats').innerHTML = ''; } // 搜索相册函数 async function searchAlbums() { await debouncedSearch(); } // 性能监控 function logPerformance() { if ('performance' in window) { // 使用更可靠的方式获取页面加载时间 const calculateLoadTime = () => { const navigationTiming = performance.getEntriesByType('navigation')[0]; if (navigationTiming && navigationTiming.loadEventEnd > 0 && navigationTiming.navigationStart > 0) { const loadTime = navigationTiming.loadEventEnd - navigationTiming.navigationStart; console.log('页面加载时间:', loadTime, 'ms'); } else { // 备用方案:使用DOMContentLoaded时间 const domContentLoadedTime = performance.timing?.domContentLoadedEventEnd - performance.timing?.navigationStart; if (domContentLoadedTime && domContentLoadedTime > 0) { console.log('DOM加载时间:', domContentLoadedTime, 'ms'); } else { console.log('页面加载时间: 无法计算'); } } }; // 如果页面已经加载完成,直接计算 if (document.readyState === 'complete') { calculateLoadTime(); } else { // 否则等待页面加载完成 window.addEventListener('load', calculateLoadTime); } } } // 移动端优化:防止双击缩放 function preventDoubleTapZoom() { if (isTouchDevice) { let lastTouchEnd = 0; document.addEventListener('touchend', function (event) { const now = (new Date()).getTime(); if (now - lastTouchEnd <= 300) { event.preventDefault(); } lastTouchEnd = now; }, false); } } // 预加载关键资源 function preloadCriticalResources() { // 预加载字体文件(CSS文件不应该预加载,因为已经在HTML中引用了) const fontResources = [ '/assets/webfonts/fa-solid-900.woff2', '/assets/webfonts/fa-brands-400.woff2', '/assets/webfonts/fa-regular-400.woff2' ]; fontResources.forEach(resource => { const link = document.createElement('link'); link.rel = 'preload'; link.href = resource; link.as = 'font'; link.crossOrigin = 'anonymous'; document.head.appendChild(link); }); // 预加载第一屏可能需要的图片 setTimeout(() => { const firstScreenImages = [ '/assets/placeholder.svg' ]; firstScreenImages.forEach(img => { const preload = document.createElement('link'); preload.rel = 'preload'; preload.href = img; preload.as = 'image'; document.head.appendChild(preload); }); }, 100); } // 优化滚动性能 function optimizeScrollPerformance() { // 使用requestAnimationFrame优化滚动 let ticking = false; function updateOnScroll() { // 在滚动时暂停非关键任务 if (!ticking) { requestAnimationFrame(() => { // 延迟加载非关键图片 delayNonCriticalImages(); ticking = false; }); ticking = true; } } window.addEventListener('scroll', updateOnScroll, {passive: true}); } // 延迟加载非关键图片 function delayNonCriticalImages() { const nonCriticalImages = document.querySelectorAll('img[data-delayed]'); nonCriticalImages.forEach(img => { if (isElementInViewport(img)) { const src = img.getAttribute('data-delayed'); if (src) { img.src = src; img.removeAttribute('data-delayed'); } } }); } // 检查元素是否在视口中 function isElementInViewport(el) { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } // 初始化性能监控和移动端优化 logPerformance(); preventDoubleTapZoom(); // 预加载关键资源 preloadCriticalResources(); // 优化滚动性能 optimizeScrollPerformance(); // 打开相册详情 function openAlbum(albumId) { window.location.href = `/album?id=${albumId}`; } // 随机打开相册 function openRandomAlbum() { // 添加随机动画效果 const randomButton = document.querySelector('.random-button'); randomButton.style.transform = 'scale(0.95)'; randomButton.disabled = true; // 显示加载状态 const originalText = randomButton.textContent; randomButton.textContent = '随机加载中...'; // 调用新的随机相册API fetch(`${API_BASE}/album/random`) .then(response => { if (!response.ok) { if (response.status === 404) { throw new Error('暂无相册数据,请稍后再试'); } throw new Error('获取随机相册失败'); } return response.json(); }) .then(randomAlbum => { // 恢复按钮状态 setTimeout(() => { randomButton.style.transform = ''; randomButton.disabled = false; randomButton.textContent = originalText; }, 200); // 跳转到随机相册 window.location.href = `/album?id=${randomAlbum.id}`; }) .catch(error => { // 恢复按钮状态 setTimeout(() => { randomButton.style.transform = ''; randomButton.disabled = false; randomButton.textContent = originalText; }, 200); alert(error.message); }); } // 显示收藏夹 function showFavorites() { // 设置当前在收藏页 isInFavoritesPage = true; // 从后端API获取收藏列表 fetch(`${API_BASE}/favorites`) .then(response => { if (!response.ok) { throw new Error('获取收藏列表失败'); } return response.json(); }) .then(favoriteImages => { // 始终显示收藏夹视图(包括空状态) displayFavorites(favoriteImages); }) .catch(error => { console.error('获取收藏列表失败:', error); alert('获取收藏列表失败,请稍后重试'); }); } // 显示收藏夹内容 function displayFavorites(favoriteImages) { const container = document.getElementById('albums-container'); container.innerHTML = ` ${favoriteImages.length === 0 ? `

收藏夹空空如也

快去收藏一些喜欢的图片吧!

` : `${favoriteImages.map((fav, index) => `
${fav.image.title || '收藏的图片'}
${formatDate(fav.favorite.created_at)} ${fav.image.width}×${fav.image.height}
`).join('')} `} `; // 更新统计信息 - 显示收藏数量 document.getElementById('stats').innerHTML = `

我的收藏夹

共收藏了 ${favoriteImages.length} 张图片

`; // 初始化图片懒加载,确保收藏的图片被加载 initLazyLoading(); } // 格式化日期 function formatDate(dateString) { const date = new Date(dateString); return date.toLocaleDateString('zh-CN', { year: 'numeric', month: 'short', day: 'numeric' }); } // 返回首页 function backToHome() { // 重置收藏页标记 isInFavoritesPage = false; // 重新加载首页相册 loadAlbums(true); } // 全局变量存储收藏列表和当前预览索引 let currentFavorites = []; let currentPreviewIndex = -1; // 预览收藏的图片 function previewFavorite(index) { // 获取收藏列表 fetch(`${API_BASE}/favorites`) .then(response => { if (!response.ok) { throw new Error('获取收藏列表失败'); } return response.json(); }) .then(favorites => { if (favorites && favorites.length > index) { currentFavorites = favorites; currentPreviewIndex = index; showPreviewModal(index); } else { alert('图片不存在或已被删除'); } }) .catch(error => { console.error('预览图片失败:', error); alert('预览图片失败,请稍后重试'); }); } // 显示预览模态框 function showPreviewModal(index) { const favorite = currentFavorites[index]; // 构建模态框HTML const modalHtml = `
来自: ${favorite.album_title}
${index + 1} / ${currentFavorites.length}
${favorite.image.title || '预览图片'}
`; // 添加到页面 document.body.insertAdjacentHTML('beforeend', modalHtml); // 显示模态框 setTimeout(() => { const modal = document.getElementById('previewModal'); modal.classList.add('active'); }, 10); // 监听键盘事件 document.addEventListener('keydown', handlePreviewKeydown); } // 关闭预览模态框 function closePreviewModal() { const modal = document.getElementById('previewModal'); if (modal) { modal.classList.remove('active'); setTimeout(() => { modal.remove(); }, 300); } // 移除键盘事件监听 document.removeEventListener('keydown', handlePreviewKeydown); } // 导航预览图片 function navigatePreview(direction) { const newIndex = currentPreviewIndex + direction; if (newIndex >= 0 && newIndex < currentFavorites.length) { updatePreviewContent(newIndex); } } // 更新预览内容(不关闭面板) function updatePreviewContent(newIndex) { const favorite = currentFavorites[newIndex]; currentPreviewIndex = newIndex; // 更新标题和相册信息 const titleElement = document.querySelector('.preview-title h3'); const infoElement = document.querySelector('.preview-info'); if (titleElement) titleElement.textContent = favorite.image.title || '未命名图片'; if (infoElement) infoElement.textContent = `来自: ${favorite.album_title}`; // 更新计数器 const counterElement = document.querySelector('.preview-counter'); if (counterElement) counterElement.textContent = `${newIndex + 1} / ${currentFavorites.length}`; // 更新导航按钮状态 const prevButton = document.querySelector('.preview-prev'); const nextButton = document.querySelector('.preview-next'); if (prevButton) prevButton.disabled = newIndex === 0; if (nextButton) nextButton.disabled = newIndex === currentFavorites.length - 1; // 更新元数据 const metaElements = document.querySelectorAll('.preview-meta .meta-item'); if (metaElements.length >= 3) { metaElements[0].innerHTML = ` ${formatDate(favorite.favorite.created_at)}`; metaElements[1].innerHTML = ` ${favorite.image.width} × ${favorite.image.height}`; } // 更新操作按钮 const openAlbumButton = document.querySelector('.preview-action:first-child'); const removeButton = document.querySelector('.preview-remove'); if (openAlbumButton) { openAlbumButton.onclick = () => openFavoriteImage(favorite.favorite.album_id); } if (removeButton) { removeButton.onclick = () => removeFavoriteFromPreview(favorite.favorite.id); } // 更新图片 const imageElement = document.getElementById('preview-image'); if (imageElement) { // 显示加载状态 imageElement.style.opacity = '0'; // 加载新图片 const newImage = new Image(); newImage.src = `${API_BASE}/image/${favorite.image.id}`; newImage.alt = favorite.image.title || '预览图片'; newImage.className = 'preview-image'; newImage.onload = function () { // 替换图片 if (imageElement.parentNode) { imageElement.parentNode.replaceChild(newImage, imageElement); // 重新设置ID newImage.id = 'preview-image'; } newImage.style.opacity = '1'; }; newImage.onerror = function () { // 图片加载失败 imageElement.innerHTML = '图片加载失败'; }; } } // 处理键盘事件 function handlePreviewKeydown(event) { if (event.key === 'Escape') { closePreviewModal(); } else if (event.key === 'ArrowLeft') { navigatePreview(-1); } else if (event.key === 'ArrowRight') { navigatePreview(1); } } // 从预览中移除收藏 function removeFavoriteFromPreview(favoriteId) { if (confirm('确定要从收藏夹移除这张图片吗?')) { fetch(`${API_BASE}/favorites/${favoriteId}`, { method: 'DELETE' }) .then(response => { if (!response.ok) { throw new Error('取消收藏失败'); } return response.json(); }) .then(() => { closePreviewModal(); // 重新显示收藏夹 showFavorites(); }) .catch(error => { console.error('取消收藏失败:', error); alert('取消收藏失败,请稍后重试'); }); } } // 从收藏夹移除图片 function removeFavorite(event, favoriteId) { event.stopPropagation(); // 阻止事件冒泡 if (confirm('确定要从收藏夹移除这张图片吗?')) { fetch(`${API_BASE}/favorites/${favoriteId}`, { method: 'DELETE' }) .then(response => { if (!response.ok) { throw new Error('取消收藏失败'); } return response.json(); }) .then(() => { // 重新显示收藏夹 showFavorites(); }) .catch(error => { console.error('取消收藏失败:', error); alert('取消收藏失败,请稍后重试'); }); } } // 打开收藏的图片 function openFavoriteImage(favoriteId) { // 这里可以跳转到对应的相册页面 // 在实际实现中,我们需要根据favoriteId获取相册信息 window.location.href = `/album?id=${favoriteId}`; } // ============================================================ // 标签和人物发现功能 // ============================================================ // 加载热门标签和人物数据 async function loadDiscoverData() { try { // 并行加载 const [tagsResp, peopleResp] = await Promise.all([ fetch(`${API_BASE}/tags/popular?limit=40`), fetch(`${API_BASE}/recommend/popular-persons?limit=30`) ]); if (tagsResp.ok) { const tags = await tagsResp.json(); if (tags && tags.length > 0) { renderTagCloud(tags); } } if (peopleResp.ok) { const people = await peopleResp.json(); if (people && people.length > 0) { renderPeopleCloud(people); } } } catch (error) { console.warn('加载发现数据失败:', error); } } // 渲染标签云 function renderTagCloud(tags) { const section = document.getElementById('tags-section'); const cloud = document.getElementById('tag-cloud'); if (!section || !cloud || !tags.length) return; section.style.display = 'block'; // 计算标签大小范围 const maxCount = Math.max(...tags.map(t => t.album_cnt || t.count || 1)); const minCount = Math.min(...tags.map(t => t.album_cnt || t.count || 1)); cloud.innerHTML = tags.map(tag => { const count = tag.album_cnt || tag.count || 1; const name = tag.tag || tag.name || ''; // 计算字体大小 (12px - 22px) const ratio = maxCount === minCount ? 0.5 : (count - minCount) / (maxCount - minCount); const fontSize = 12 + ratio * 10; // 计算热度颜色 const hue = 210 - ratio * 50; // 蓝色到紫色 const opacity = 0.6 + ratio * 0.4; return ` ${name} (${count}) `; }).join(''); } // 渲染热门人物 function renderPeopleCloud(people) { const section = document.getElementById('people-section'); const cloud = document.getElementById('people-cloud'); if (!section || !cloud || !people.length) return; section.style.display = 'block'; cloud.innerHTML = people.map(p => { const name = p.name || p.display_name || ''; const albumCount = p.total_albums || 0; const imageCount = p.total_images || 0; return `
${name.charAt(0)}
${name}
${albumCount} 相册 · ${imageCount} 图
`; }).join(''); } // 按标签筛选 async function filterByTag(tag) { currentFilter = { type: 'tag', value: tag }; showFilterStatus(`标签: ${tag}`); try { showSkeleton(6); const response = await fetch(`${API_BASE}/tags/search?tag=${encodeURIComponent(tag)}&limit=200`); if (!response.ok) throw new Error('搜索失败'); const results = await response.json(); displayAlbums(results); updateStats(results); initLazyLoading(); } catch (error) { console.error('标签筛选失败:', error); showError('标签筛选失败'); } } // 按人物筛选 async function filterByPerson(personName) { currentFilter = { type: 'person', value: personName }; showFilterStatus(`人物: ${personName}`); try { showSkeleton(6); const response = await fetch(`${API_BASE}/people/search?q=${encodeURIComponent(personName)}`); if (!response.ok) throw new Error('搜索失败'); const persons = await response.json(); if (persons && persons.length > 0) { // 先尝试通过人物详情获取相册 const personId = persons[0].id; try { const detailResp = await fetch(`${API_BASE}/people/${encodeURIComponent(personName)}`); if (detailResp.ok) { const detail = await detailResp.json(); if (detail && detail.albums) { displayAlbums(detail.albums); updateStats(detail.albums); initLazyLoading(); return; } } } catch (e) { // 回退到标题搜索 } } // 回退:使用标题搜索 await performServerSearch(personName); } catch (error) { console.error('人物筛选失败:', error); // 回退到标题搜索 await performServerSearch(personName); } } // 显示筛选状态 function showFilterStatus(text) { const status = document.getElementById('filter-status'); const label = document.getElementById('current-filter'); if (status && label) { label.textContent = text; status.style.display = 'flex'; } } // 清除筛选 function clearFilter() { currentFilter = null; const status = document.getElementById('filter-status'); if (status) status.style.display = 'none'; // 清空搜索框 const searchInput = document.getElementById('search-input'); if (searchInput) searchInput.value = ''; // 重新加载所有相册 loadAlbums(true); } // 折叠/展开区域 function toggleSection(name) { collapsedSections[name] = !collapsedSections[name]; const cloudId = name === 'people' ? 'people-cloud' : 'tag-cloud'; const cloud = document.getElementById(cloudId); const btn = document.querySelector(`#${name}-section .section-toggle i`); if (cloud) { if (collapsedSections[name]) { cloud.style.display = 'none'; btn.className = 'fas fa-chevron-down'; } else { cloud.style.display = ''; btn.className = 'fas fa-chevron-up'; } } } // 导出函数供全局使用 window.searchAlbums = searchAlbums; window.openRandomAlbum = openRandomAlbum; window.showFavorites = showFavorites; window.openAlbum = openAlbum; window.backToHome = backToHome; window.loadAlbums = loadAlbums; window.removeFavorite = removeFavorite; window.previewFavorite = previewFavorite; window.openFavoriteImage = openFavoriteImage; window.removeFavoriteFromPreview = removeFavoriteFromPreview; window.filterByTag = filterByTag; window.filterByPerson = filterByPerson; window.clearFilter = clearFilter; window.toggleSection = toggleSection;