feat: 增强图像查看器功能并添加“全部下载”按钮在imageViewerModal中添加了全屏查看、左右翻页和删除图像功能。在index.html中新增了downloadAllImagesBtn按钮,用于一键下载所有生成的图像。script.js中相应实现了这些新功能的逻辑。
This commit is contained in:
27
index.html
27
index.html
@@ -137,7 +137,12 @@
|
|||||||
|
|
||||||
<!-- 生成的图像画廊 -->
|
<!-- 生成的图像画廊 -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<h5><i class="fas fa-images me-2"></i>生成的图像</h5>
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h5 class="mb-0"><i class="fas fa-images me-2"></i>生成的图像</h5>
|
||||||
|
<button class="btn btn-success" id="downloadAllImagesBtn" style="display: none;">
|
||||||
|
<i class="fas fa-download me-2"></i>全部下载
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<div class="image-gallery" id="imageGallery"></div>
|
<div class="image-gallery" id="imageGallery"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,20 +154,34 @@
|
|||||||
|
|
||||||
<!-- 新的图像查看模态框 -->
|
<!-- 新的图像查看模态框 -->
|
||||||
<div class="modal fade" id="imageViewerModal" tabindex="-1" aria-labelledby="imageViewerModalLabel" aria-hidden="true">
|
<div class="modal fade" id="imageViewerModal" tabindex="-1" aria-labelledby="imageViewerModalLabel" aria-hidden="true">
|
||||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
<div class="modal-dialog modal-dialog-centered modal-fullscreen">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h5 class="modal-title" id="imageViewerModalLabel">图像查看</h5>
|
<h5 class="modal-title" id="imageViewerModalLabel">图像查看</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body text-center">
|
<div class="modal-body text-center position-relative">
|
||||||
|
<!-- 左翻页按钮 -->
|
||||||
|
<button type="button" class="btn btn-light position-absolute top-50 start-0 translate-middle-y" id="prevImageBtn">
|
||||||
|
<i class="fas fa-chevron-left"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- 图像显示区域 -->
|
||||||
<img id="viewerModalImage" src="" alt="查看图像" class="img-fluid">
|
<img id="viewerModalImage" src="" alt="查看图像" class="img-fluid">
|
||||||
|
|
||||||
|
<!-- 右翻页按钮 -->
|
||||||
|
<button type="button" class="btn btn-light position-absolute top-50 end-0 translate-middle-y" id="nextImageBtn">
|
||||||
|
<i class="fas fa-chevron-right"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
<button type="button" class="btn btn-danger" id="viewerDeleteImage">
|
||||||
|
<i class="fas fa-trash me-2"></i>删除图像
|
||||||
|
</button>
|
||||||
<button type="button" class="btn btn-primary" id="viewerDownloadImage">
|
<button type="button" class="btn btn-primary" id="viewerDownloadImage">
|
||||||
<i class="fas fa-download me-2"></i>下载图像
|
<i class="fas fa-download me-2"></i>下载图像
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
345
script.js
345
script.js
@@ -11,6 +11,8 @@ let currentSettings = {
|
|||||||
timeout: 600,
|
timeout: 600,
|
||||||
proxy: ''
|
proxy: ''
|
||||||
};
|
};
|
||||||
|
let currentImageIndex = 0; // 当前查看的图像索引
|
||||||
|
let currentModalInstance = null; // 当前模态框实例
|
||||||
|
|
||||||
// 配置常量
|
// 配置常量
|
||||||
const CONFIG = {
|
const CONFIG = {
|
||||||
@@ -112,7 +114,7 @@ const utils = {
|
|||||||
await indexedDBStorage.cleanupOldMessages();
|
await indexedDBStorage.cleanupOldMessages();
|
||||||
await indexedDBStorage.cleanupOldImages();
|
await indexedDBStorage.cleanupOldImages();
|
||||||
|
|
||||||
console.log('IndexedDB 存储空间检查和清理完成');
|
//console.log('IndexedDB 存储空间检查和清理完成');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('存储空间检查失败:', error);
|
console.error('存储空间检查失败:', error);
|
||||||
}
|
}
|
||||||
@@ -120,9 +122,9 @@ const utils = {
|
|||||||
|
|
||||||
// 检查存储状态 - 调试用
|
// 检查存储状态 - 调试用
|
||||||
checkStorageStatus: async function() {
|
checkStorageStatus: async function() {
|
||||||
console.log('=== 存储状态检查 ===');
|
//console.log('=== 存储状态检查 ===');
|
||||||
console.log('IndexedDB 支持:', indexedDBStorage.isSupported);
|
//console.log('IndexedDB 支持:', indexedDBStorage.isSupported);
|
||||||
console.log('IndexedDB 数据库:', indexedDBStorage.db);
|
//console.log('IndexedDB 数据库:', indexedDBStorage.db);
|
||||||
|
|
||||||
if (indexedDBStorage.isSupported) {
|
if (indexedDBStorage.isSupported) {
|
||||||
try {
|
try {
|
||||||
@@ -130,17 +132,17 @@ const utils = {
|
|||||||
const chatHistory = await indexedDBStorage.getChatHistory();
|
const chatHistory = await indexedDBStorage.getChatHistory();
|
||||||
const images = await indexedDBStorage.getGeneratedImages();
|
const images = await indexedDBStorage.getGeneratedImages();
|
||||||
|
|
||||||
console.log('IndexedDB 数据统计:');
|
//console.log('IndexedDB 数据统计:');
|
||||||
console.log(`- 设置: ${settings ? '已保存' : '未保存'}`);
|
//console.log(`- 设置: ${settings ? '已保存' : '未保存'}`);
|
||||||
console.log(`- 聊天记录: ${chatHistory.length} 条`);
|
//console.log(`- 聊天记录: ${chatHistory.length} 条`);
|
||||||
console.log(`- 生成图像: ${images.length} 个`);
|
//console.log(`- 生成图像: ${images.length} 个`);
|
||||||
|
|
||||||
chatHistory.forEach((msg, idx) => {
|
chatHistory.forEach((msg, idx) => {
|
||||||
console.log(` 聊天 ${idx}: ${msg.role} - ${msg.content.substring(0, 50)}...`);
|
//console.log(` 聊天 ${idx}: ${msg.role} - ${msg.content.substring(0, 50)}...`);
|
||||||
});
|
});
|
||||||
|
|
||||||
images.forEach((img, idx) => {
|
images.forEach((img, idx) => {
|
||||||
console.log(` 图像 ${idx}: URL长度 ${img.url ? img.url.length : 0}`);
|
//console.log(` 图像 ${idx}: URL长度 ${img.url ? img.url.length : 0}`);
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('读取 IndexedDB 数据失败:', error);
|
console.error('读取 IndexedDB 数据失败:', error);
|
||||||
@@ -150,24 +152,24 @@ const utils = {
|
|||||||
|
|
||||||
// 检查事件绑定 - 调试用
|
// 检查事件绑定 - 调试用
|
||||||
checkEventBindings: function() {
|
checkEventBindings: function() {
|
||||||
console.log('=== 事件绑定检查 ===');
|
//console.log('=== 事件绑定检查 ===');
|
||||||
const containers = document.querySelectorAll('.image-clickable-container');
|
const containers = document.querySelectorAll('.image-clickable-container');
|
||||||
console.log(`找到 ${containers.length} 个可点击图像容器`);
|
//console.log(`找到 ${containers.length} 个可点击图像容器`);
|
||||||
|
|
||||||
containers.forEach((container, idx) => {
|
containers.forEach((container, idx) => {
|
||||||
const img = container.querySelector('img');
|
const img = container.querySelector('img');
|
||||||
const tooltip = container.querySelector('.image-preview-tooltip');
|
const tooltip = container.querySelector('.image-preview-tooltip');
|
||||||
console.log(`容器 ${idx}:`, {
|
// console.log(`容器 ${idx}:`, {
|
||||||
src: img ? img.src.substring(0, 50) + '...' : '无图片',
|
// src: img ? img.src.substring(0, 50) + '...' : '无图片',
|
||||||
hasTooltip: !!tooltip,
|
// hasTooltip: !!tooltip,
|
||||||
tooltipText: tooltip ? tooltip.textContent : '无',
|
// tooltipText: tooltip ? tooltip.textContent : '无',
|
||||||
classList: container.classList.toString()
|
// classList: container.classList.toString()
|
||||||
});
|
// });
|
||||||
});
|
});
|
||||||
|
|
||||||
// 测试点击第一个容器
|
// 测试点击第一个容器
|
||||||
if (containers.length > 0) {
|
if (containers.length > 0) {
|
||||||
console.log('尝试点击第一个图像容器...');
|
//console.log('尝试点击第一个图像容器...');
|
||||||
containers[0].click();
|
containers[0].click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,13 +208,13 @@ const indexedDBStorage = {
|
|||||||
request.onsuccess = (event) => {
|
request.onsuccess = (event) => {
|
||||||
this.db = event.target.result;
|
this.db = event.target.result;
|
||||||
this.isSupported = true;
|
this.isSupported = true;
|
||||||
console.log('IndexedDB 初始化成功');
|
//console.log('IndexedDB 初始化成功');
|
||||||
resolve(true);
|
resolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
request.onupgradeneeded = (event) => {
|
request.onupgradeneeded = (event) => {
|
||||||
const db = event.target.result;
|
const db = event.target.result;
|
||||||
console.log('正在创建/升级数据库结构...');
|
//console.log('正在创建/升级数据库结构...');
|
||||||
|
|
||||||
// 创建设置存储
|
// 创建设置存储
|
||||||
if (!db.objectStoreNames.contains(CONFIG.INDEXED_DB.STORES.SETTINGS)) {
|
if (!db.objectStoreNames.contains(CONFIG.INDEXED_DB.STORES.SETTINGS)) {
|
||||||
@@ -513,14 +515,14 @@ const indexedDBStorage = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('开始从 localStorage 迁移数据到 IndexedDB...');
|
//console.log('开始从 localStorage 迁移数据到 IndexedDB...');
|
||||||
|
|
||||||
// 迁移设置
|
// 迁移设置
|
||||||
const savedSettings = localStorage.getItem(CONFIG.STORAGE_KEYS.SETTINGS);
|
const savedSettings = localStorage.getItem(CONFIG.STORAGE_KEYS.SETTINGS);
|
||||||
if (savedSettings) {
|
if (savedSettings) {
|
||||||
const settings = JSON.parse(savedSettings);
|
const settings = JSON.parse(savedSettings);
|
||||||
await this.saveSettings(settings);
|
await this.saveSettings(settings);
|
||||||
console.log('设置已迁移到 IndexedDB');
|
//console.log('设置已迁移到 IndexedDB');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 迁移聊天历史
|
// 迁移聊天历史
|
||||||
@@ -530,7 +532,7 @@ const indexedDBStorage = {
|
|||||||
for (const msg of messages) {
|
for (const msg of messages) {
|
||||||
await this.addChatMessage(msg.role, msg.content);
|
await this.addChatMessage(msg.role, msg.content);
|
||||||
}
|
}
|
||||||
console.log(`已迁移 ${messages.length} 条聊天记录到 IndexedDB`);
|
//console.log(`已迁移 ${messages.length} 条聊天记录到 IndexedDB`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 迁移图像记录
|
// 迁移图像记录
|
||||||
@@ -540,15 +542,56 @@ const indexedDBStorage = {
|
|||||||
for (const img of images) {
|
for (const img of images) {
|
||||||
await this.addGeneratedImage(img.id, img.url);
|
await this.addGeneratedImage(img.id, img.url);
|
||||||
}
|
}
|
||||||
console.log(`已迁移 ${images.length} 条图像记录到 IndexedDB`);
|
//console.log(`已迁移 ${images.length} 条图像记录到 IndexedDB`);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('数据迁移完成');
|
//console.log('数据迁移完成');
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('数据迁移失败:', error);
|
console.error('数据迁移失败:', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除生成的图像记录
|
||||||
|
deleteGeneratedImage: async function(imageId) {
|
||||||
|
if (!this.isSupported) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const transaction = this.db.transaction([CONFIG.INDEXED_DB.STORES.GENERATED_IMAGES], 'readwrite');
|
||||||
|
const store = transaction.objectStore(CONFIG.INDEXED_DB.STORES.GENERATED_IMAGES);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
// 遍历所有记录查找匹配的imageId
|
||||||
|
const request = store.openCursor();
|
||||||
|
|
||||||
|
request.onsuccess = (event) => {
|
||||||
|
const cursor = event.target.result;
|
||||||
|
if (cursor) {
|
||||||
|
const record = cursor.value;
|
||||||
|
if (record.imageId === imageId) {
|
||||||
|
// 找到匹配的记录,删除它
|
||||||
|
const deleteRequest = cursor.delete();
|
||||||
|
deleteRequest.onsuccess = () => resolve(true);
|
||||||
|
deleteRequest.onerror = () => reject(deleteRequest.error);
|
||||||
|
} else {
|
||||||
|
// 继续查找下一条记录
|
||||||
|
cursor.continue();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 遍历完成但没有找到记录
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
request.onerror = () => reject(request.error);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('IndexedDB 删除图像记录失败:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -769,19 +812,30 @@ const uiController = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (removeBtn) {
|
if (removeBtn) {
|
||||||
removeBtn.addEventListener('click', (e) => {
|
removeBtn.addEventListener('click', async (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
app.removeGeneratedImage(imageId);
|
await app.removeGeneratedImage(imageId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加到内存中的图像记录
|
// 添加到内存中的图像记录
|
||||||
generatedImages.push({ id: imageId, url: imageUrl });
|
generatedImages.push({ id: imageId, url: imageUrl });
|
||||||
|
|
||||||
|
// 显示"全部下载"按钮
|
||||||
|
this.updateDownloadAllButtonVisibility();
|
||||||
|
|
||||||
// 保存到存储 - 优先使用 IndexedDB
|
// 保存到存储 - 优先使用 IndexedDB
|
||||||
await this.saveGeneratedImages(imageId, imageUrl);
|
await this.saveGeneratedImages(imageId, imageUrl);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 更新"全部下载"按钮的可见性
|
||||||
|
updateDownloadAllButtonVisibility: function() {
|
||||||
|
const downloadAllBtn = document.getElementById('downloadAllImagesBtn');
|
||||||
|
if (downloadAllBtn) {
|
||||||
|
downloadAllBtn.style.display = generatedImages.length > 0 ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// 添加占位图像
|
// 添加占位图像
|
||||||
addImagePlaceholder: function(index, total) {
|
addImagePlaceholder: function(index, total) {
|
||||||
const gallery = document.getElementById('imageGallery');
|
const gallery = document.getElementById('imageGallery');
|
||||||
@@ -864,15 +918,18 @@ const uiController = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (removeBtn) {
|
if (removeBtn) {
|
||||||
removeBtn.addEventListener('click', (e) => {
|
removeBtn.addEventListener('click', async (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
app.removeGeneratedImage(imageId);
|
await app.removeGeneratedImage(imageId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加到内存中的图像记录
|
// 添加到内存中的图像记录
|
||||||
generatedImages.push({ id: imageId, url: imageUrl });
|
generatedImages.push({ id: imageId, url: imageUrl });
|
||||||
|
|
||||||
|
// 显示"全部下载"按钮
|
||||||
|
this.updateDownloadAllButtonVisibility();
|
||||||
|
|
||||||
// 保存到存储 - 优先使用 IndexedDB
|
// 保存到存储 - 优先使用 IndexedDB
|
||||||
this.saveGeneratedImages(imageId, imageUrl);
|
this.saveGeneratedImages(imageId, imageUrl);
|
||||||
},
|
},
|
||||||
@@ -897,7 +954,7 @@ const uiController = {
|
|||||||
|
|
||||||
|
|
||||||
// 新的查看大图功能
|
// 新的查看大图功能
|
||||||
viewLargeImage: function(imageUrl) {
|
viewLargeImage: async function(imageUrl) {
|
||||||
try {
|
try {
|
||||||
const modalElement = document.getElementById('imageViewerModal');
|
const modalElement = document.getElementById('imageViewerModal');
|
||||||
if (!modalElement) {
|
if (!modalElement) {
|
||||||
@@ -913,12 +970,18 @@ const uiController = {
|
|||||||
|
|
||||||
const modalImage = document.getElementById('viewerModalImage');
|
const modalImage = document.getElementById('viewerModalImage');
|
||||||
const downloadButton = document.getElementById('viewerDownloadImage');
|
const downloadButton = document.getElementById('viewerDownloadImage');
|
||||||
|
const deleteButton = document.getElementById('viewerDeleteImage');
|
||||||
|
const prevButton = document.getElementById('prevImageBtn');
|
||||||
|
const nextButton = document.getElementById('nextImageBtn');
|
||||||
|
|
||||||
if (!modalImage) {
|
if (!modalImage) {
|
||||||
utils.showNotification('无法打开图像查看:找不到图像元素', 'danger');
|
utils.showNotification('无法打开图像查看:找不到图像元素', 'danger');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 找到当前图像在generatedImages中的索引
|
||||||
|
currentImageIndex = generatedImages.findIndex(img => img.url === imageUrl);
|
||||||
|
|
||||||
// 设置图像源
|
// 设置图像源
|
||||||
modalImage.src = imageUrl;
|
modalImage.src = imageUrl;
|
||||||
modalImage.onerror = function() {
|
modalImage.onerror = function() {
|
||||||
@@ -932,9 +995,140 @@ const uiController = {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置删除按钮功能
|
||||||
|
if (deleteButton) {
|
||||||
|
deleteButton.onclick = function() {
|
||||||
|
// 保存当前图像ID
|
||||||
|
const currentImageId = generatedImages[currentImageIndex].id;
|
||||||
|
|
||||||
|
// 删除当前图像
|
||||||
|
app.removeGeneratedImage(currentImageId).then(() => {
|
||||||
|
// 检查删除后是否还有图像
|
||||||
|
if (generatedImages.length === 0) {
|
||||||
|
// 没有图像了,关闭模态框
|
||||||
|
currentModalInstance.hide();
|
||||||
|
} else {
|
||||||
|
// 更新当前图像索引
|
||||||
|
if (currentImageIndex >= generatedImages.length) {
|
||||||
|
// 如果删除的是最后一张,显示上一张
|
||||||
|
currentImageIndex = generatedImages.length - 1;
|
||||||
|
}
|
||||||
|
// 如果索引仍然有效,显示图像
|
||||||
|
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
||||||
|
modalImage.src = generatedImages[currentImageIndex].url;
|
||||||
|
// 更新删除按钮对应的图像ID
|
||||||
|
deleteButton.onclick = function() {
|
||||||
|
const newCurrentImageId = generatedImages[currentImageIndex].id;
|
||||||
|
app.removeGeneratedImage(newCurrentImageId).then(() => {
|
||||||
|
// 再次检查删除后是否还有图像
|
||||||
|
if (generatedImages.length === 0) {
|
||||||
|
currentModalInstance.hide();
|
||||||
|
} else {
|
||||||
|
// 更新当前图像索引
|
||||||
|
if (currentImageIndex >= generatedImages.length) {
|
||||||
|
currentImageIndex = generatedImages.length - 1;
|
||||||
|
}
|
||||||
|
// 如果索引仍然有效,显示图像
|
||||||
|
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
||||||
|
modalImage.src = generatedImages[currentImageIndex].url;
|
||||||
|
// 更新删除按钮对应的图像ID
|
||||||
|
deleteButton.onclick = arguments.callee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新翻页按钮状态
|
||||||
|
uiController.updateNavigationButtons();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置翻页按钮功能
|
||||||
|
if (prevButton) {
|
||||||
|
prevButton.onclick = function() {
|
||||||
|
if (currentImageIndex > 0) {
|
||||||
|
currentImageIndex--;
|
||||||
|
modalImage.src = generatedImages[currentImageIndex].url;
|
||||||
|
// 更新删除按钮对应的图像ID
|
||||||
|
deleteButton.onclick =async function() {
|
||||||
|
// 保存当前图像ID
|
||||||
|
const currentImageId = generatedImages[currentImageIndex].id;
|
||||||
|
|
||||||
|
// 删除当前图像
|
||||||
|
await app.removeGeneratedImage(currentImageId);
|
||||||
|
|
||||||
|
// 检查删除后是否还有图像
|
||||||
|
if (generatedImages.length === 0) {
|
||||||
|
// 没有图像了,关闭模态框
|
||||||
|
currentModalInstance.hide();
|
||||||
|
} else {
|
||||||
|
// 更新当前图像索引
|
||||||
|
if (currentImageIndex >= generatedImages.length) {
|
||||||
|
// 如果删除的是最后一张,显示上一张
|
||||||
|
currentImageIndex = generatedImages.length - 1;
|
||||||
|
}
|
||||||
|
// 如果索引仍然有效,显示图像
|
||||||
|
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
||||||
|
modalImage.src = generatedImages[currentImageIndex].url;
|
||||||
|
// 更新删除按钮对应的图像ID
|
||||||
|
deleteButton.onclick = arguments.callee;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新翻页按钮状态
|
||||||
|
uiController.updateNavigationButtons();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextButton) {
|
||||||
|
nextButton.onclick = function() {
|
||||||
|
if (currentImageIndex < generatedImages.length - 1) {
|
||||||
|
currentImageIndex++;
|
||||||
|
modalImage.src = generatedImages[currentImageIndex].url;
|
||||||
|
// 更新删除按钮对应的图像ID
|
||||||
|
deleteButton.onclick = function() {
|
||||||
|
// 保存当前图像ID
|
||||||
|
const currentImageId = generatedImages[currentImageIndex].id;
|
||||||
|
|
||||||
|
// 删除当前图像
|
||||||
|
app.removeGeneratedImage(currentImageId).then(() => {
|
||||||
|
// 检查删除后是否还有图像
|
||||||
|
if (generatedImages.length === 0) {
|
||||||
|
// 没有图像了,关闭模态框
|
||||||
|
currentModalInstance.hide();
|
||||||
|
} else {
|
||||||
|
// 更新当前图像索引
|
||||||
|
if (currentImageIndex >= generatedImages.length) {
|
||||||
|
// 如果删除的是最后一张,显示上一张
|
||||||
|
currentImageIndex = generatedImages.length - 1;
|
||||||
|
}
|
||||||
|
// 如果索引仍然有效,显示图像
|
||||||
|
if (currentImageIndex >= 0 && currentImageIndex < generatedImages.length) {
|
||||||
|
modalImage.src = generatedImages[currentImageIndex].url;
|
||||||
|
// 更新删除按钮对应的图像ID
|
||||||
|
deleteButton.onclick = arguments.callee;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新翻页按钮状态
|
||||||
|
uiController.updateNavigationButtons();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新翻页按钮状态
|
||||||
|
this.updateNavigationButtons();
|
||||||
|
|
||||||
// 创建并显示模态框
|
// 创建并显示模态框
|
||||||
const modal = new bootstrap.Modal(modalElement);
|
currentModalInstance = new bootstrap.Modal(modalElement);
|
||||||
modal.show();
|
currentModalInstance.show();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
utils.showNotification(`无法打开图像查看: ${error.message}`, 'danger');
|
utils.showNotification(`无法打开图像查看: ${error.message}`, 'danger');
|
||||||
@@ -948,6 +1142,20 @@ const uiController = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 更新翻页按钮状态
|
||||||
|
updateNavigationButtons: function() {
|
||||||
|
const prevButton = document.getElementById('prevImageBtn');
|
||||||
|
const nextButton = document.getElementById('nextImageBtn');
|
||||||
|
|
||||||
|
if (prevButton) {
|
||||||
|
prevButton.style.display = currentImageIndex > 0 ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextButton) {
|
||||||
|
nextButton.style.display = currentImageIndex < generatedImages.length - 1 ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// 显示图像预览
|
// 显示图像预览
|
||||||
displayImagePreview: function(imageData) {
|
displayImagePreview: function(imageData) {
|
||||||
const preview = document.getElementById('imagePreview');
|
const preview = document.getElementById('imagePreview');
|
||||||
@@ -1113,9 +1321,9 @@ const uiController = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (removeBtn) {
|
if (removeBtn) {
|
||||||
removeBtn.addEventListener('click', (e) => {
|
removeBtn.addEventListener('click', async (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
app.removeGeneratedImage(img.id);
|
await app.removeGeneratedImage(img.id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1125,7 +1333,7 @@ const uiController = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 移除生成的图像
|
// 移除生成的图像
|
||||||
removeGeneratedImage: function(imageId) {
|
removeGeneratedImage: async function(imageId) {
|
||||||
// 从内存中移除
|
// 从内存中移除
|
||||||
generatedImages = generatedImages.filter(img => img.id !== imageId);
|
generatedImages = generatedImages.filter(img => img.id !== imageId);
|
||||||
|
|
||||||
@@ -1139,7 +1347,17 @@ const uiController = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 不需要再更新存储,因为 IndexedDB 会自动管理
|
// 从IndexedDB中移除
|
||||||
|
if (indexedDBStorage.isSupported) {
|
||||||
|
try {
|
||||||
|
await indexedDBStorage.deleteGeneratedImage(imageId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('从IndexedDB删除图像记录失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新"全部下载"按钮的可见性
|
||||||
|
this.updateDownloadAllButtonVisibility();
|
||||||
},
|
},
|
||||||
|
|
||||||
// 保存设置
|
// 保存设置
|
||||||
@@ -1233,10 +1451,10 @@ const app = {
|
|||||||
|
|
||||||
// 初始化 IndexedDB
|
// 初始化 IndexedDB
|
||||||
try {
|
try {
|
||||||
console.log('正在初始化 IndexedDB...');
|
//console.log('正在初始化 IndexedDB...');
|
||||||
const indexedDBSupported = await indexedDBStorage.init();
|
const indexedDBSupported = await indexedDBStorage.init();
|
||||||
if (indexedDBSupported) {
|
if (indexedDBSupported) {
|
||||||
console.log('IndexedDB 初始化成功,将优先使用 IndexedDB 存储');
|
//console.log('IndexedDB 初始化成功,将优先使用 IndexedDB 存储');
|
||||||
// 尝试迁移数据
|
// 尝试迁移数据
|
||||||
await indexedDBStorage.migrateFromLocalStorage();
|
await indexedDBStorage.migrateFromLocalStorage();
|
||||||
} else {
|
} else {
|
||||||
@@ -1250,6 +1468,10 @@ const app = {
|
|||||||
await utils.checkAndCleanStorage();
|
await utils.checkAndCleanStorage();
|
||||||
await utils.checkStorageStatus();
|
await utils.checkStorageStatus();
|
||||||
await uiController.loadSettings();
|
await uiController.loadSettings();
|
||||||
|
|
||||||
|
// 初始化"全部下载"按钮的可见性
|
||||||
|
uiController.updateDownloadAllButtonVisibility();
|
||||||
|
|
||||||
console.log('OpenRouter Image Generator initialized');
|
console.log('OpenRouter Image Generator initialized');
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1274,6 +1496,14 @@ const app = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 全部下载按钮事件
|
||||||
|
const downloadAllBtn = document.getElementById('downloadAllImagesBtn');
|
||||||
|
if (downloadAllBtn) {
|
||||||
|
downloadAllBtn.addEventListener('click', function() {
|
||||||
|
app.downloadAllImages();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 设置变化时自动保存
|
// 设置变化时自动保存
|
||||||
const inputs = ['apiKey', 'baseUrl', 'model', 'timeout', 'proxy'];
|
const inputs = ['apiKey', 'baseUrl', 'model', 'timeout', 'proxy'];
|
||||||
inputs.forEach(id => {
|
inputs.forEach(id => {
|
||||||
@@ -1524,8 +1754,8 @@ const app = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 移除生成的图像
|
// 移除生成的图像
|
||||||
removeGeneratedImage: function(imageId) {
|
removeGeneratedImage: async function(imageId) {
|
||||||
uiController.removeGeneratedImage(imageId);
|
await uiController.removeGeneratedImage(imageId);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 下载图像
|
// 下载图像
|
||||||
@@ -1536,6 +1766,34 @@ const app = {
|
|||||||
link.click();
|
link.click();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 全部下载图像
|
||||||
|
downloadAllImages: function() {
|
||||||
|
if (generatedImages.length === 0) {
|
||||||
|
utils.showNotification('没有可下载的图像', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建一个临时通知
|
||||||
|
utils.showNotification(`正在下载 ${generatedImages.length} 张图像...`, 'info');
|
||||||
|
|
||||||
|
// 逐个下载图像
|
||||||
|
generatedImages.forEach((img, index) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = img.url;
|
||||||
|
link.download = `generated-image-${Date.now()}-${index + 1}.png`;
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
// 最后一个图像下载完成后显示通知
|
||||||
|
if (index === generatedImages.length - 1) {
|
||||||
|
setTimeout(() => {
|
||||||
|
utils.showNotification(`已成功下载 ${generatedImages.length} 张图像`, 'success');
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}, index * 200); // 每个图像下载间隔200ms,避免浏览器阻止多个下载
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
// 复制图像URL
|
// 复制图像URL
|
||||||
copyImageUrl: function(imageUrl) {
|
copyImageUrl: function(imageUrl) {
|
||||||
navigator.clipboard.writeText(imageUrl).then(() => {
|
navigator.clipboard.writeText(imageUrl).then(() => {
|
||||||
@@ -1559,7 +1817,7 @@ const app = {
|
|||||||
// 清除 IndexedDB 数据
|
// 清除 IndexedDB 数据
|
||||||
const cleared = await indexedDBStorage.clearAllData();
|
const cleared = await indexedDBStorage.clearAllData();
|
||||||
if (cleared) {
|
if (cleared) {
|
||||||
console.log('IndexedDB 数据已清除');
|
//console.log('IndexedDB 数据已清除');
|
||||||
} else {
|
} else {
|
||||||
console.error('IndexedDB 清除失败');
|
console.error('IndexedDB 清除失败');
|
||||||
}
|
}
|
||||||
@@ -1594,6 +1852,7 @@ window.testConnection = () => app.testConnection();
|
|||||||
window.sendMessage = () => app.sendMessage();
|
window.sendMessage = () => app.sendMessage();
|
||||||
window.sendBatchMessage = () => app.sendBatchMessage();
|
window.sendBatchMessage = () => app.sendBatchMessage();
|
||||||
window.downloadImage = (url) => app.downloadImage(url);
|
window.downloadImage = (url) => app.downloadImage(url);
|
||||||
|
window.downloadAllImages = () => app.downloadAllImages();
|
||||||
window.copyImageUrl = (url) => app.copyImageUrl(url);
|
window.copyImageUrl = (url) => app.copyImageUrl(url);
|
||||||
window.removeImage = (id) => app.removeImage(id);
|
window.removeImage = (id) => app.removeImage(id);
|
||||||
window.removeGeneratedImage = (id) => app.removeGeneratedImage(id);
|
window.removeGeneratedImage = (id) => app.removeGeneratedImage(id);
|
||||||
@@ -1604,6 +1863,6 @@ window.checkEventBindings = () => utils.checkEventBindings();
|
|||||||
window.clearIndexedDB = async () => {
|
window.clearIndexedDB = async () => {
|
||||||
if (indexedDBStorage.isSupported) {
|
if (indexedDBStorage.isSupported) {
|
||||||
const cleared = await indexedDBStorage.clearAllData();
|
const cleared = await indexedDBStorage.clearAllData();
|
||||||
console.log('IndexedDB 已清空:', cleared);
|
//console.log('IndexedDB 已清空:', cleared);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
61
styles.css
61
styles.css
@@ -404,7 +404,8 @@ body {
|
|||||||
|
|
||||||
/* 图像查看模态框样式 */
|
/* 图像查看模态框样式 */
|
||||||
#viewerModalImage {
|
#viewerModalImage {
|
||||||
max-height: 80vh;
|
max-height: 85vh;
|
||||||
|
max-width: 95vw;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
|
||||||
@@ -412,7 +413,63 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#viewerModalImage:hover {
|
#viewerModalImage:hover {
|
||||||
transform: scale(1.02);
|
//transform: scale(1.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 全屏模态框样式 */
|
||||||
|
.modal-fullscreen .modal-dialog {
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-fullscreen .modal-content {
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-fullscreen .modal-body {
|
||||||
|
height: calc(100% - 120px);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 翻页按钮样式 */
|
||||||
|
#prevImageBtn, #nextImageBtn {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-radius: 50%;
|
||||||
|
opacity: 0.7;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#prevImageBtn:hover, #nextImageBtn:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#prevImageBtn {
|
||||||
|
left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nextImageBtn {
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 暗色背景下的按钮样式 */
|
||||||
|
.modal-fullscreen .modal-body .btn-light {
|
||||||
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
|
border-color: rgba(255, 255, 255, 0.3);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-fullscreen .modal-body .btn-light:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.3);
|
||||||
|
border-color: rgba(255, 255, 255, 0.5);
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 图像查看模态框特定样式 */
|
/* 图像查看模态框特定样式 */
|
||||||
|
|||||||
Reference in New Issue
Block a user