1005 lines
34 KiB
JavaScript
1005 lines
34 KiB
JavaScript
// 全局变量
|
||
let allAlbums = [];
|
||
let searchTimeout = null;
|
||
let currentPage = 1;
|
||
let albumsPerPage = 50; // 减少每页数量,提高加载速度
|
||
let isLoadingMore = false;
|
||
let hasMoreAlbums = true;
|
||
let lazyLoadObserver = null;
|
||
|
||
// API基础URL
|
||
const API_BASE = '/api';
|
||
|
||
// 设备检测
|
||
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');
|
||
}
|
||
|
||
loadAlbums();
|
||
initSearch();
|
||
initInfiniteScroll();
|
||
});
|
||
|
||
// 初始化搜索功能
|
||
function initSearch() {
|
||
const searchInput = document.getElementById('search-input');
|
||
|
||
// 防抖搜索
|
||
searchInput.addEventListener('input', function () {
|
||
clearTimeout(searchTimeout);
|
||
searchTimeout = setTimeout(debouncedSearch, 300);
|
||
});
|
||
|
||
// 移动端优化:搜索框聚焦时自动滚动到可视区域
|
||
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 handleScroll() {
|
||
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 (isLoadingMore || !hasMoreAlbums) return;
|
||
|
||
isLoadingMore = true;
|
||
try {
|
||
await loadAlbums();
|
||
} catch (error) {
|
||
console.error('加载更多相册失败:', error);
|
||
showLoadMoreError();
|
||
} finally {
|
||
isLoadingMore = false;
|
||
}
|
||
}
|
||
|
||
// 显示加载更多错误
|
||
function showLoadMoreError() {
|
||
const container = document.getElementById('albums-container');
|
||
const errorElement = document.createElement('div');
|
||
errorElement.className = 'load-more-error';
|
||
errorElement.innerHTML = `
|
||
<div class="error-content">
|
||
<i class="fas fa-exclamation-triangle"></i>
|
||
<span>加载失败,<a href="javascript:void(0)" onclick="loadMoreAlbums()">点击重试</a></span>
|
||
</div>
|
||
`;
|
||
|
||
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(() => `
|
||
<div class="skeleton-card">
|
||
<div class="skeleton-cover skeleton"></div>
|
||
<div class="skeleton-content">
|
||
<div class="skeleton-title skeleton"></div>
|
||
<div class="skeleton-meta">
|
||
<div class="skeleton-meta-item skeleton"></div>
|
||
<div class="skeleton-meta-item skeleton"></div>
|
||
</div>
|
||
<div class="skeleton-button skeleton"></div>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// 显示加载更多指示器
|
||
function showLoadingMore() {
|
||
const container = document.getElementById('albums-container');
|
||
const loadingIndicator = document.createElement('div');
|
||
loadingIndicator.id = 'loading-more';
|
||
loadingIndicator.className = 'loading-more';
|
||
loadingIndicator.innerHTML = `
|
||
<div class="loading-spinner">
|
||
<i class="fas fa-spinner fa-spin"></i>
|
||
<span>加载更多相册...</span>
|
||
</div>
|
||
`;
|
||
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/thumbnail/${album.cover_image_id}`;
|
||
coverImageUrl = '/assets/placeholder.svg'; // 初始使用占位图
|
||
}
|
||
|
||
// 格式化日期
|
||
const createdDate = new Date(album.created_at).toLocaleDateString('zh-CN');
|
||
|
||
return `
|
||
<div class="album-card" data-album-id="${album.id}">
|
||
<div class="album-cover">
|
||
<img
|
||
src="${coverImageUrl}"
|
||
${dataSrc ? `data-src="${dataSrc}"` : ''}
|
||
alt="${album.title}"
|
||
class="lazy"
|
||
onerror="this.src='/assets/placeholder.svg'"
|
||
>
|
||
</div>
|
||
<div class="album-info">
|
||
<h3>${album.title}</h3>
|
||
<div class="album-meta">
|
||
<span><i class="fas fa-images"></i> ${album.image_count} 张图片</span>
|
||
<span><i class="fas fa-calendar"></i> ${createdDate}</span>
|
||
</div>
|
||
<a href="/album?id=${album.id}" class="view-button">
|
||
<i class="fas fa-eye"></i> 查看相册
|
||
</a>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}).join('');
|
||
|
||
// 移除加载指示器并添加新相册
|
||
hideLoadingMore();
|
||
container.insertAdjacentHTML('beforeend', newAlbumsHTML);
|
||
}
|
||
|
||
// 加载所有相册
|
||
async function loadAlbums(reset = false) {
|
||
try {
|
||
if (reset) {
|
||
currentPage = 1;
|
||
allAlbums = [];
|
||
hasMoreAlbums = true;
|
||
const container = document.getElementById('albums-container');
|
||
container.innerHTML = '';
|
||
}
|
||
|
||
if (!hasMoreAlbums) return;
|
||
|
||
// 显示骨架屏
|
||
if (currentPage === 1) {
|
||
showSkeleton();
|
||
} else {
|
||
showLoadingMore();
|
||
}
|
||
|
||
const response = await fetch(`${API_BASE}/albums`);
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP error! status: ${response.status}`);
|
||
}
|
||
|
||
const newAlbums = await response.json();
|
||
|
||
// 检查是否还有更多数据
|
||
if (newAlbums.length < albumsPerPage) {
|
||
hasMoreAlbums = false;
|
||
}
|
||
|
||
// 合并到现有相册列表
|
||
allAlbums = [...allAlbums, ...newAlbums];
|
||
|
||
if (currentPage === 1) {
|
||
displayAlbums(allAlbums);
|
||
} else {
|
||
appendAlbums(newAlbums);
|
||
}
|
||
|
||
updateStats(allAlbums);
|
||
|
||
// 初始化图片懒加载
|
||
initLazyLoading();
|
||
|
||
// 预加载下一批图片
|
||
preloadNextBatchImages();
|
||
|
||
currentPage++;
|
||
|
||
// 隐藏加载更多指示器
|
||
hideLoadingMore();
|
||
} catch (error) {
|
||
console.error('加载相册失败:', error);
|
||
showError('加载相册数据失败,请刷新页面重试');
|
||
hideLoadingMore();
|
||
}
|
||
}
|
||
|
||
// 搜索相册
|
||
// 防抖搜索函数
|
||
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 = `
|
||
<div class="search-hint">
|
||
<i class="fas fa-search"></i>
|
||
<h3>未在当前页面找到 "${searchTerm}"</h3>
|
||
<p>尝试:</p>
|
||
<ul>
|
||
<li>继续滚动加载更多相册</li>
|
||
<li>使用更精确的搜索词</li>
|
||
<li><button class="btn-primary" onclick="performServerSearch('${searchTerm}')">在全站搜索 "${searchTerm}"</button></li>
|
||
</ul>
|
||
</div>
|
||
`;
|
||
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 = '<div class="no-results"><i class="fas fa-search"></i><br>没有找到匹配的相册</div>';
|
||
return;
|
||
}
|
||
|
||
container.innerHTML = albums.map(album => {
|
||
// 处理封面图片URL - 使用懒加载
|
||
let coverImageUrl = '/assets/placeholder.svg';
|
||
let dataSrc = '';
|
||
|
||
if (album.cover_image_id) {
|
||
dataSrc = `/api/thumbnail/${album.cover_image_id}`;
|
||
coverImageUrl = '/assets/placeholder.svg'; // 初始使用占位图
|
||
}
|
||
|
||
// 格式化日期
|
||
const createdDate = new Date(album.created_at).toLocaleDateString('zh-CN');
|
||
|
||
return `
|
||
<div class="album-card" data-album-id="${album.id}">
|
||
<div class="album-cover">
|
||
<img
|
||
src="${coverImageUrl}"
|
||
${dataSrc ? `data-src="${dataSrc}"` : ''}
|
||
alt="${album.title}"
|
||
class="lazy"
|
||
onerror="this.src='/assets/placeholder.svg'"
|
||
>
|
||
</div>
|
||
<div class="album-info">
|
||
<h3>${album.title}</h3>
|
||
<div class="album-meta">
|
||
<span><i class="fas fa-images"></i> ${album.image_count} 张图片</span>
|
||
<span><i class="fas fa-calendar"></i> ${createdDate}</span>
|
||
</div>
|
||
<a href="/album?id=${album.id}" class="view-button">
|
||
<i class="fas fa-eye"></i> 查看相册
|
||
</a>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}).join('');
|
||
}
|
||
|
||
// 初始化图片懒加载
|
||
function initLazyLoading() {
|
||
if (!lazyLoadObserver) {
|
||
lazyLoadObserver = new IntersectionObserver((entries) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting) {
|
||
const img = entry.target;
|
||
if (img.dataset.src) {
|
||
img.src = img.dataset.src;
|
||
img.classList.remove('lazy');
|
||
lazyLoadObserver.unobserve(img);
|
||
}
|
||
}
|
||
});
|
||
}, {
|
||
rootMargin: '100px 0px', // 提前100px开始加载
|
||
threshold: 0.01
|
||
});
|
||
}
|
||
|
||
const lazyImages = document.querySelectorAll('img.lazy');
|
||
lazyImages.forEach(img => {
|
||
lazyLoadObserver.observe(img);
|
||
});
|
||
}
|
||
|
||
// 预加载下一批图片
|
||
function preloadNextBatchImages() {
|
||
const imagesToPreload = [];
|
||
const visibleImages = document.querySelectorAll('img.lazy');
|
||
|
||
// 预加载前10张可见图片
|
||
visibleImages.forEach((img, index) => {
|
||
if (index < 10 && img.dataset.src) {
|
||
imagesToPreload.push(img.dataset.src);
|
||
}
|
||
});
|
||
|
||
// 使用link预加载
|
||
imagesToPreload.forEach(src => {
|
||
const link = document.createElement('link');
|
||
link.rel = 'preload';
|
||
link.as = 'image';
|
||
link.href = src;
|
||
document.head.appendChild(link);
|
||
});
|
||
}
|
||
|
||
// 更新统计信息
|
||
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 = `<div class="no-results"><i class="fas fa-exclamation-triangle"></i><br>${message}</div>`;
|
||
document.getElementById('stats').innerHTML = '';
|
||
}
|
||
|
||
// 搜索相册函数
|
||
async function searchAlbums() {
|
||
await debouncedSearch();
|
||
}
|
||
|
||
|
||
// 性能监控
|
||
function logPerformance() {
|
||
if ('performance' in window) {
|
||
window.addEventListener('load', () => {
|
||
setTimeout(() => {
|
||
const navigationTiming = performance.getEntriesByType('navigation')[0];
|
||
if (navigationTiming && navigationTiming.loadEventEnd && navigationTiming.navigationStart) {
|
||
const loadTime = navigationTiming.loadEventEnd - navigationTiming.navigationStart;
|
||
console.log('页面加载时间:', loadTime, 'ms');
|
||
} else {
|
||
console.log('页面加载时间: 无法计算');
|
||
}
|
||
}, 0);
|
||
});
|
||
}
|
||
}
|
||
|
||
// 移动端优化:防止双击缩放
|
||
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和字体
|
||
const criticalResources = [
|
||
'/assets/css/font-awesome.css',
|
||
'/assets/css/style.css',
|
||
'/assets/webfonts/fa-solid-900.woff2'
|
||
];
|
||
|
||
criticalResources.forEach(resource => {
|
||
const link = document.createElement('link');
|
||
link.rel = 'preload';
|
||
link.href = resource;
|
||
link.as = resource.endsWith('.css') ? 'style' : '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 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() {
|
||
// 从后端API获取收藏列表
|
||
fetch(`${API_BASE}/favorites`)
|
||
.then(response => {
|
||
if (!response.ok) {
|
||
throw new Error('获取收藏列表失败');
|
||
}
|
||
return response.json();
|
||
})
|
||
.then(favoriteImages => {
|
||
if (favoriteImages.length === 0) {
|
||
alert('收藏夹为空,快去收藏一些喜欢的图片吧!');
|
||
return;
|
||
}
|
||
|
||
// 创建收藏夹页面或跳转到收藏夹视图
|
||
displayFavorites(favoriteImages);
|
||
})
|
||
.catch(error => {
|
||
console.error('获取收藏列表失败:', error);
|
||
alert('获取收藏列表失败,请稍后重试');
|
||
});
|
||
}
|
||
|
||
// 显示收藏夹内容
|
||
function displayFavorites(favoriteImages) {
|
||
const container = document.getElementById('albums-container');
|
||
|
||
container.innerHTML = `
|
||
${favoriteImages.length === 0 ? `
|
||
<div class="empty-favorites">
|
||
<div class="empty-icon">
|
||
<i class="fas fa-heart-broken"></i>
|
||
</div>
|
||
<h3>收藏夹空空如也</h3>
|
||
<p>快去收藏一些喜欢的图片吧!</p>
|
||
<button class="explore-button" onclick="loadAlbums()">
|
||
<i class="fas fa-compass"></i> 探索相册
|
||
</button>
|
||
</div>
|
||
` : `${favoriteImages.map((fav, index) => `
|
||
<div class="favorite-card" onclick="openFavoriteImage('${fav.favorite.album_id}')">
|
||
<div class="card-image">
|
||
<img src="${API_BASE}/thumbnail/${fav.image.id}"
|
||
alt="${fav.image.title || '收藏的图片'}"
|
||
loading="lazy">
|
||
<div class="card-overlay">
|
||
<div class="overlay-content">
|
||
<button class="quick-view" onclick="event.stopPropagation(); previewFavorite(${index})">
|
||
<i class="fas fa-expand"></i>
|
||
</button>
|
||
<button class="remove-favorite" onclick="removeFavorite(event, '${fav.favorite.id}')">
|
||
<i class="fas fa-trash"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="favorite-badge">
|
||
<i class="fas fa-heart"></i>
|
||
</div>
|
||
</div>
|
||
<div class="card-content">
|
||
<div class="image-meta">
|
||
<span class="meta-item">
|
||
<i class="fas fa-calendar"></i>
|
||
${formatDate(fav.favorite.created_at)}
|
||
</span>
|
||
<span class="meta-item">
|
||
<i class="fas fa-ruler-combined"></i>
|
||
${fav.image.width}×${fav.image.height}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`).join('')}
|
||
`}
|
||
`;
|
||
|
||
// 更新统计信息 - 显示收藏数量
|
||
document.getElementById('stats').innerHTML = `<div class="favorites-header">
|
||
<div class="header-content">
|
||
<div class="header-left">
|
||
<div class="favorites-icon">
|
||
<i class="fas fa-heart"></i>
|
||
</div>
|
||
<div class="header-info">
|
||
<h1>我的收藏夹</h1>
|
||
<p class="favorites-count">共收藏了 <span class="count-number">${favoriteImages.length}</span> 张图片</p>
|
||
</div>
|
||
</div>
|
||
<div class="header-right">
|
||
<div class="action-buttons">
|
||
<button class="back-button" onclick="loadAlbums()">
|
||
<i class="fas fa-arrow-left"></i> 返回首页
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>`;
|
||
}
|
||
|
||
// 格式化日期
|
||
function formatDate(dateString) {
|
||
const date = new Date(dateString);
|
||
return date.toLocaleDateString('zh-CN', {
|
||
year: 'numeric',
|
||
month: 'short',
|
||
day: 'numeric'
|
||
});
|
||
}
|
||
|
||
// 全局变量存储收藏列表和当前预览索引
|
||
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 = `
|
||
<div class="preview-modal" id="previewModal">
|
||
<div class="preview-overlay" onclick="closePreviewModal()"></div>
|
||
<div class="preview-container">
|
||
<div class="preview-header">
|
||
<div class="preview-title">
|
||
<span class="preview-info">来自: ${favorite.album_title}</span>
|
||
</div>
|
||
<div class="preview-actions">
|
||
<button class="preview-nav preview-prev" onclick="navigatePreview(-1)" ${index === 0 ? 'disabled' : ''}>
|
||
<i class="fas fa-chevron-left"></i>
|
||
</button>
|
||
<span class="preview-counter">${index + 1} / ${currentFavorites.length}</span>
|
||
<button class="preview-nav preview-next" onclick="navigatePreview(1)" ${index === currentFavorites.length - 1 ? 'disabled' : ''}>
|
||
<i class="fas fa-chevron-right"></i>
|
||
</button>
|
||
<button class="preview-close" onclick="closePreviewModal()">
|
||
<i class="fas fa-times"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="preview-content">
|
||
<div class="preview-image-container">
|
||
<img src="${API_BASE}/original/${favorite.image.id}"
|
||
alt="${favorite.image.title || '预览图片'}"
|
||
class="preview-image"
|
||
id="preview-image"
|
||
loading="eager">
|
||
</div>
|
||
</div>
|
||
<div class="preview-footer">
|
||
<div class="preview-meta">
|
||
<span class="meta-item">
|
||
<i class="fas fa-calendar"></i>
|
||
${formatDate(favorite.favorite.created_at)}
|
||
</span>
|
||
<span class="meta-item">
|
||
<i class="fas fa-ruler-combined"></i>
|
||
${favorite.image.width} × ${favorite.image.height}
|
||
</span>
|
||
<span class="meta-item">
|
||
<i class="fas fa-heart"></i>
|
||
已收藏
|
||
</span>
|
||
</div>
|
||
<div class="preview-controls">
|
||
<button class="preview-action" onclick="openFavoriteImage('${favorite.favorite.album_id}')">
|
||
<i class="fas fa-folder-open"></i> 打开相册
|
||
</button>
|
||
<button class="preview-action preview-remove" onclick="removeFavoriteFromPreview('${favorite.favorite.id}')">
|
||
<i class="fas fa-trash"></i> 取消收藏
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
|
||
// 添加到页面
|
||
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 = `<i class="fas fa-calendar"></i> ${formatDate(favorite.favorite.created_at)}`;
|
||
metaElements[1].innerHTML = `<i class="fas fa-ruler-combined"></i> ${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}/original/${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 = '<i class="fas fa-exclamation-triangle"></i><span>图片加载失败</span>';
|
||
};
|
||
}
|
||
}
|
||
|
||
// 处理键盘事件
|
||
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 sortFavorites(mode) {
|
||
// 这里可以实现排序功能
|
||
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}`;
|
||
}
|
||
|
||
// 导出函数供全局使用
|
||
window.searchAlbums = searchAlbums;
|
||
window.openRandomAlbum = openRandomAlbum;
|
||
window.showFavorites = showFavorites; |