/**
* 图片展示组件
*/
class ImageGallery {
constructor() {
this.images = [];
this.selectedImages = [];
// 下载设置相关
this.lastSavePath = localStorage.getItem('lastSavePath') || '首次下载';
this.pendingDownload = null; // 待下载的图片数据
this.isBatchDownload = false; // 是否批量下载
this.initElements();
this.bindEvents();
}
/**
* 初始化DOM元素
*/
initElements() {
this.galleryGrid = document.getElementById('galleryGrid');
this.emptyState = document.getElementById('emptyState');
this.totalImages = document.getElementById('totalImages');
this.successImages = document.getElementById('successImages');
this.failedImages = document.getElementById('failedImages');
this.downloadAllBtn = document.getElementById('downloadAll');
// 图片预览模态框元素
this.imageModal = document.getElementById('imageModal');
this.modalImage = document.getElementById('modalImage');
this.modalClose = document.getElementById('modalClose');
this.modalDownload = document.getElementById('modalDownload');
this.modalCopy = document.getElementById('modalCopy');
// 下载设置模态框元素
this.downloadModal = document.getElementById('downloadModal');
this.downloadModalClose = document.getElementById('downloadModalClose');
this.downloadFilename = document.getElementById('downloadFilename');
this.lastSavePathEl = document.getElementById('lastSavePath');
this.downloadConfirmBtn = document.getElementById('downloadConfirmBtn');
this.downloadCancelBtn = document.getElementById('downloadCancelBtn');
this.currentModalImage = null;
}
/**
* 绑定事件
*/
bindEvents() {
// 批量下载按钮
this.downloadAllBtn.addEventListener('click', () => {
this.downloadAllImages();
});
// 图片预览模态框事件
this.modalClose.addEventListener('click', () => {
this.closeModal();
});
this.modalDownload.addEventListener('click', () => {
this.downloadModalImage();
});
this.modalCopy.addEventListener('click', () => {
this.copyModalImage();
});
// 点击模态框背景关闭
this.imageModal.addEventListener('click', (e) => {
if (e.target === this.imageModal) {
this.closeModal();
}
});
// 下载设置模态框事件
this.downloadModalClose.addEventListener('click', () => {
this.closeDownloadModal();
});
this.downloadCancelBtn.addEventListener('click', () => {
this.closeDownloadModal();
});
this.downloadConfirmBtn.addEventListener('click', () => {
this.confirmDownload();
});
// 点击下载模态框背景关闭
this.downloadModal.addEventListener('click', (e) => {
if (e.target === this.downloadModal) {
this.closeDownloadModal();
}
});
// ESC键关闭模态框
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
if (this.downloadModal.style.display === 'block') {
this.closeDownloadModal();
} else if (this.imageModal.style.display === 'block') {
this.closeModal();
}
}
});
// Enter键确认下载
this.downloadFilename.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
this.confirmDownload();
}
});
}
/**
* 添加图片到展示区
*/
addImage(imageData) {
const imageId = `image_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const imageItem = {
id: imageId,
index: imageData.index,
status: imageData.status,
data: imageData.image_data,
error: imageData.error,
timestamp: imageData.timestamp,
batchId: imageData.batchId // 添加批次ID支持
};
this.images.push(imageItem);
this.renderImage(imageItem);
this.updateStats();
this.updateEmptyState();
}
/**
* 更新图片状态
*/
updateImageStatus(index, status, data = null, error = null, batchId = null) {
let image;
if (batchId) {
// 如果提供了批次ID,优先使用批次ID和索引进行匹配
image = this.images.find(img => img.batchId === batchId && img.index === index);
} else {
// 兼容旧逻辑:从后往前查找状态为generating的图片
const candidates = this.images.filter(img => img.index === index && img.status === 'generating');
image = candidates[candidates.length - 1]; // 取最后一个
}
if (image) {
image.status = status;
if (data) image.data = data;
if (error) image.error = error;
this.rerenderImage(image);
this.updateStats();
}
}
/**
* 渲染单个图片
*/
renderImage(imageItem) {
const card = document.createElement('div');
card.className = 'image-card';
card.dataset.imageId = imageItem.id;
card.innerHTML = this.getImageCardHTML(imageItem);
this.galleryGrid.appendChild(card);
this.bindImageEvents(card, imageItem);
}
/**
* 重新渲染图片
*/
rerenderImage(imageItem) {
const card = this.galleryGrid.querySelector(`[data-image-id="${imageItem.id}"]`);
if (card) {
card.innerHTML = this.getImageCardHTML(imageItem);
this.bindImageEvents(card, imageItem);
}
}
/**
* 获取图片卡片HTML
*/
getImageCardHTML(imageItem) {
switch (imageItem.status) {
case 'pending':
return `
等待中
`;
case 'generating':
return `
生成中
`;
case 'success':
return `
成功
`;
case 'error':
return `
生成失败
${imageItem.error || '未知错误'}
失败
`;
default:
return `
`;
}
}
/**
* 绑定图片事件
*/
bindImageEvents(card, imageItem) {
// 查看原图
const viewBtn = card.querySelector('.btn-view');
if (viewBtn) {
viewBtn.addEventListener('click', () => {
this.viewImage(imageItem);
});
}
// 下载图片
const downloadBtn = card.querySelector('.btn-download');
if (downloadBtn) {
downloadBtn.addEventListener('click', () => {
this.downloadImage(imageItem);
});
}
// 复制图片
const copyBtn = card.querySelector('.btn-copy');
if (copyBtn) {
copyBtn.addEventListener('click', () => {
this.copyImage(imageItem);
});
}
// 删除图片
const deleteBtn = card.querySelector('.btn-delete');
if (deleteBtn) {
deleteBtn.addEventListener('click', () => {
this.deleteImage(imageItem);
});
}
// 重试按钮
const retryBtn = card.querySelector('.btn-retry');
if (retryBtn) {
retryBtn.addEventListener('click', () => {
this.retryImage(imageItem);
});
}
// 双击查看原图
const img = card.querySelector('img');
if (img) {
img.addEventListener('dblclick', () => {
this.viewImage(imageItem);
});
}
}
/**
* 查看原图
*/
viewImage(imageItem) {
this.currentModalImage = imageItem;
this.modalImage.src = imageItem.data;
this.imageModal.style.display = 'block';
}
/**
* 关闭模态框
*/
closeModal() {
this.imageModal.style.display = 'none';
this.currentModalImage = null;
}
/**
* 生成默认时间戳文件名
*/
generateDefaultFilename() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `img_${year}${month}${day}_${hours}${minutes}${seconds}`;
}
/**
* 打开下载设置对话框
*/
openDownloadModal(imageData, isBatch = false) {
this.pendingDownload = imageData;
this.isBatchDownload = isBatch;
// 设置默认文件名
this.downloadFilename.value = this.generateDefaultFilename();
// 显示上次保存路径
this.lastSavePathEl.textContent = this.lastSavePath;
// 显示模态框
this.downloadModal.style.display = 'block';
// 聚焦到文件名输入框并选中内容
setTimeout(() => {
this.downloadFilename.focus();
this.downloadFilename.select();
}, 100);
}
/**
* 关闭下载设置对话框
*/
closeDownloadModal() {
this.downloadModal.style.display = 'none';
this.pendingDownload = null;
this.isBatchDownload = false;
}
/**
* 确认下载
*/
async confirmDownload() {
const filename = this.downloadFilename.value.trim();
if (!filename) {
this.showToast('请输入文件名', 'warning');
return;
}
// 保存待下载数据(因为关闭对话框会清空)
const downloadData = this.pendingDownload;
const isBatch = this.isBatchDownload;
// 先关闭对话框,避免阻塞系统文件选择器
this.closeDownloadModal();
if (isBatch) {
// 批量下载 - 使用目录选择器
await this.executeBatchDownload(filename, downloadData);
} else {
// 单张下载 - 使用另存为对话框
await this.executeSingleDownload(filename, downloadData);
}
}
/**
* 执行单张图片下载(使用另存为对话框)
*/
async executeSingleDownload(filename, imageData) {
const finalFilename = `${filename}.jpg`;
console.log('开始下载单张图片:', finalFilename);
console.log('图片数据存在:', !!imageData?.data);
const result = await window.ImageUtils.downloadImageWithPicker(imageData.data, finalFilename);
console.log('下载结果:', result);
if (result.success) {
// 更新上次保存路径
if (result.filename) {
this.lastSavePath = `上次文件: ${result.filename}`;
localStorage.setItem('lastSavePath', this.lastSavePath);
}
this.showToast('图片下载成功', 'success');
} else if (result.cancelled) {
// 用户取消,不提示
} else {
this.showToast('图片下载失败', 'error');
}
}
/**
* 执行批量下载(使用目录选择器)
*/
async executeBatchDownload(filenamePrefix, images) {
// 尝试使用目录选择器
const result = await window.ImageUtils.downloadMultipleWithPicker(images, filenamePrefix);
if (result.success) {
// 更新上次保存路径
this.lastSavePath = `上次目录: ${result.dirName}`;
localStorage.setItem('lastSavePath', this.lastSavePath);
this.showToast(`成功保存 ${result.count} 张图片到 ${result.dirName}`, 'success');
} else if (result.cancelled) {
// 用户取消,不提示
} else if (result.notSupported) {
// 浏览器不支持目录选择,回退到传统逐个下载
this.showToast('浏览器不支持选择文件夹,将逐个下载', 'warning');
await this.fallbackBatchDownload(filenamePrefix, images);
} else {
this.showToast('批量下载失败: ' + (result.error || '未知错误'), 'error');
}
}
/**
* 回退的批量下载方式(逐个下载到默认下载目录)
*/
async fallbackBatchDownload(filenamePrefix, images) {
let successCount = 0;
for (let i = 0; i < images.length; i++) {
const img = images[i];
const finalFilename = `${filenamePrefix}_${i + 1}.jpg`;
if (window.ImageUtils.downloadImage(img.data, finalFilename)) {
successCount++;
}
// 添加小延迟避免浏览器阻止多个下载
if (i < images.length - 1) {
await new Promise(resolve => setTimeout(resolve, 500));
}
}
// 更新上次保存路径
this.lastSavePath = `文件名前缀: ${filenamePrefix}`;
localStorage.setItem('lastSavePath', this.lastSavePath);
if (successCount > 0) {
this.showToast(`成功下载 ${successCount} 张图片`, 'success');
} else {
this.showToast('下载失败', 'error');
}
}
/**
* 下载图片(打开设置对话框)
*/
downloadImage(imageItem) {
this.openDownloadModal(imageItem, false);
}
/**
* 下载模态框中的图片
*/
downloadModalImage() {
if (this.currentModalImage) {
this.downloadImage(this.currentModalImage);
}
}
/**
* 复制图片
*/
async copyImage(imageItem) {
try {
const success = await window.ImageUtils.copyImageToClipboard(imageItem.data);
if (success) {
this.showToast('图片已复制到剪贴板', 'success');
} else {
this.showToast('复制图片失败', 'error');
}
} catch (error) {
console.error('复制图片失败:', error);
this.showToast('复制图片失败', 'error');
}
}
/**
* 复制模态框中的图片
*/
async copyModalImage() {
if (this.currentModalImage) {
await this.copyImage(this.currentModalImage);
}
}
/**
* 删除图片
*/
deleteImage(imageItem) {
if (!confirm('确定要删除这张图片吗?')) {
return;
}
// 从数组中移除
const index = this.images.findIndex(img => img.id === imageItem.id);
if (index > -1) {
this.images.splice(index, 1);
}
// 从DOM中移除
const card = this.galleryGrid.querySelector(`[data-image-id="${imageItem.id}"]`);
if (card) {
card.remove();
}
this.updateStats();
this.updateEmptyState();
this.showToast('图片已删除', 'success');
}
/**
* 重试生成图片
*/
retryImage(imageItem) {
// 触发重试事件,由图片生成器处理
const event = new CustomEvent('retryImage', {
detail: { imageItem }
});
document.dispatchEvent(event);
}
/**
* 批量下载所有图片
*/
async downloadAllImages() {
const successImages = this.images.filter(img => img.status === 'success');
if (successImages.length === 0) {
this.showToast('没有可下载的图片', 'warning');
return;
}
// 打开下载设置对话框(批量模式)
this.openDownloadModal(successImages, true);
}
/**
* 清空所有图片
*/
clearAllImages() {
this.images = [];
this.galleryGrid.innerHTML = '';
this.updateStats();
this.updateEmptyState();
}
/**
* 更新统计信息
*/
updateStats() {
const total = this.images.length;
const success = this.images.filter(img => img.status === 'success').length;
const failed = this.images.filter(img => img.status === 'error').length;
this.totalImages.textContent = `总计: ${total}`;
this.successImages.textContent = `成功: ${success}`;
this.failedImages.textContent = `失败: ${failed}`;
// 更新下载按钮状态
this.downloadAllBtn.disabled = success === 0;
}
/**
* 更新空状态显示
*/
updateEmptyState() {
if (this.images.length === 0) {
this.emptyState.style.display = 'flex';
this.galleryGrid.style.display = 'none';
} else {
this.emptyState.style.display = 'none';
this.galleryGrid.style.display = 'grid';
}
}
/**
* 显示消息提示
*/
showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
const container = document.getElementById('toastContainer');
container.appendChild(toast);
// 3秒后自动移除
setTimeout(() => {
if (toast.parentNode) {
toast.parentNode.removeChild(toast);
}
}, 3000);
}
}
// 导出到全局
window.ImageGallery = ImageGallery;