From 431e23173080b56fb151c1f625fb03f710efd4f7 Mon Sep 17 00:00:00 2001
From: shiyue <935732994@qq.com>
Date: Fri, 29 Aug 2025 13:05:22 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9C=A8index.html=E5=92=8Cscript.js?=
=?UTF-8?q?=E4=B8=AD=E6=B7=BB=E5=8A=A0=E5=9B=BE=E5=83=8F=E6=89=B9=E9=87=8F?=
=?UTF-8?q?=E7=94=9F=E6=88=90=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
index.html | 24 +++--
script.js | 254 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
styles.css | 119 +++++++++++++++++++++++++
test.html | 138 -----------------------------
4 files changed, 390 insertions(+), 145 deletions(-)
delete mode 100644 test.html
diff --git a/index.html b/index.html
index ecffd32..ca77ec7 100644
--- a/index.html
+++ b/index.html
@@ -98,14 +98,26 @@
-
+
-
对话输入
-
diff --git a/script.js b/script.js
index d2f3fe7..3b05fc0 100644
--- a/script.js
+++ b/script.js
@@ -668,6 +668,12 @@ const uiController = {
loadingSpinner.style.display = show ? 'block' : 'none';
},
+ // 隐藏传统加载状态,用于批量生成模式
+ hideTraditionalLoading: function() {
+ const loadingSpinner = document.getElementById('loadingSpinner');
+ loadingSpinner.style.display = 'none';
+ },
+
// 添加聊天消息
addChatMessage: async function(role, content) {
const chatHistoryDiv = document.getElementById('chatHistory');
@@ -776,6 +782,119 @@ const uiController = {
await this.saveGeneratedImages(imageId, imageUrl);
},
+ // 添加占位图像
+ addImagePlaceholder: function(index, total) {
+ const gallery = document.getElementById('imageGallery');
+ const placeholderDiv = document.createElement('div');
+ placeholderDiv.className = 'image-placeholder fade-in';
+ placeholderDiv.id = `placeholder-${index}`;
+
+ placeholderDiv.innerHTML = `
+
+
+
+
+ 正在生成图像 ${index + 1}/${total}
+
+
+ `;
+
+ gallery.appendChild(placeholderDiv);
+ return placeholderDiv;
+ },
+
+ // 替换占位图像为实际图像
+ replacePlaceholderWithImage: function(placeholderId, imageUrl) {
+ const placeholder = document.getElementById(placeholderId);
+ if (!placeholder) return;
+
+ const imageId = Date.now() + Math.random();
+ placeholder.className = 'image-item fade-in';
+ placeholder.id = '';
+
+ placeholder.innerHTML = `
+

+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ // 添加事件监听器
+ const viewLargeBtn = placeholder.querySelector('.view-large-btn');
+ const downloadBtn = placeholder.querySelector('.download-btn');
+ const copyBtn = placeholder.querySelector('.copy-url-btn');
+ const removeBtn = placeholder.querySelector('.remove-btn');
+
+ if (viewLargeBtn) {
+ viewLargeBtn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ this.viewLargeImage(imageUrl);
+ });
+ }
+
+ if (downloadBtn) {
+ downloadBtn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ app.downloadImage(imageUrl);
+ });
+ }
+
+ if (copyBtn) {
+ copyBtn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ app.copyImageUrl(imageUrl);
+ });
+ }
+
+ if (removeBtn) {
+ removeBtn.addEventListener('click', (e) => {
+ e.stopPropagation();
+ app.removeGeneratedImage(imageId);
+ });
+ }
+
+ // 添加到内存中的图像记录
+ generatedImages.push({ id: imageId, url: imageUrl });
+
+ // 保存到存储 - 优先使用 IndexedDB
+ this.saveGeneratedImages(imageId, imageUrl);
+ },
+
+ // 显示批量生成状态
+ showBatchStatus: function(message, show = true) {
+ let statusDiv = document.getElementById('batchStatus');
+ if (!statusDiv) {
+ statusDiv = document.createElement('div');
+ statusDiv.id = 'batchStatus';
+ statusDiv.className = 'batch-status';
+ document.body.appendChild(statusDiv);
+ }
+
+ statusDiv.textContent = message;
+ if (show) {
+ statusDiv.classList.add('show');
+ } else {
+ statusDiv.classList.remove('show');
+ }
+ },
+
// 新的查看大图功能
viewLargeImage: function(imageUrl) {
@@ -1199,7 +1318,7 @@ const app = {
}
},
- // 发送消息
+ // 发送消息 - 生成一张图像
sendMessage: async function() {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value.trim();
@@ -1257,6 +1376,138 @@ const app = {
}
},
+ // 批量发送消息
+ sendBatchMessage: async function() {
+ const messageInput = document.getElementById('messageInput');
+ const batchCountInput = document.getElementById('batchCount');
+ const message = messageInput.value.trim();
+ const batchCount = parseInt(batchCountInput.value) || 6;
+
+ if (!message) {
+ utils.showNotification('请输入消息', 'warning');
+ return;
+ }
+
+ if (batchCount < 1 || batchCount > 10) {
+ utils.showNotification('请输入有效的生成数量(1-10)', 'warning');
+ return;
+ }
+
+ const apiKey = document.getElementById('apiKey').value;
+ if (!apiKey) {
+ utils.showNotification(ERROR_MESSAGES.NO_API_KEY, 'warning');
+ return;
+ }
+
+ // 隐藏传统加载状态,使用占位图像代替
+ uiController.hideTraditionalLoading();
+
+ // 添加用户消息到聊天历史
+ uiController.addChatMessage('user', message);
+
+ // 创建占位图像
+ const placeholders = [];
+ for (let i = 0; i < batchCount; i++) {
+ const placeholder = uiController.addImagePlaceholder(i, batchCount);
+ placeholders.push(placeholder);
+ }
+
+ // 显示批量生成状态
+ uiController.showBatchStatus(`正在批量生成 ${batchCount} 张图像...`);
+
+ let successCount = 0;
+ let failCount = 0;
+ let firstResponse = null;
+ let completedCount = 0;
+
+ // 同时发送所有请求,但每个请求完成后立即处理
+ const promises = [];
+ for (let i = 0; i < batchCount; i++) {
+ promises.push(
+ apiService.generateImage(message, uploadedImages, currentSettings)
+ .then(response => {
+ // 保存第一个响应用于添加聊天消息
+ if (!firstResponse) {
+ firstResponse = response;
+ uiController.addChatMessage('assistant', response.content);
+ }
+
+ // 显示生成的图像
+ if (response.images && response.images.length > 0) {
+ // 如果返回多个图像,为每个图像创建新的占位符
+ if (response.images.length > 1) {
+ // 移除原始占位符
+ const originalPlaceholder = document.getElementById(`placeholder-${i}`);
+ if (originalPlaceholder) {
+ originalPlaceholder.remove();
+ }
+
+ // 为每个图像添加新的图像项
+ response.images.forEach((img, imgIndex) => {
+ uiController.addGeneratedImage(img);
+ });
+ } else {
+ // 只有一个图像,直接替换占位符
+ uiController.replacePlaceholderWithImage(`placeholder-${i}`, response.images[0]);
+ }
+ successCount++;
+ } else {
+ // 移除占位符
+ const placeholder = document.getElementById(`placeholder-${i}`);
+ if (placeholder) {
+ placeholder.remove();
+ }
+ failCount++;
+ }
+
+ // 更新完成计数和状态
+ completedCount++;
+ uiController.showBatchStatus(`已完成 ${completedCount}/${batchCount} 张图像...`);
+
+ return { index: i, response };
+ })
+ .catch(error => {
+ console.error(`生成第 ${i + 1} 张图像失败:`, error);
+
+ // 移除占位符
+ const placeholder = document.getElementById(`placeholder-${i}`);
+ if (placeholder) {
+ placeholder.remove();
+ }
+
+ failCount++;
+
+ // 更新完成计数和状态
+ completedCount++;
+ uiController.showBatchStatus(`已完成 ${completedCount}/${batchCount} 张图像...`);
+
+ return { index: i, error };
+ })
+ );
+ }
+
+ // 等待所有请求完成
+ await Promise.all(promises);
+
+ // 检查存储空间
+ await utils.checkAndCleanStorage();
+
+ // 清空输入框
+ messageInput.value = '';
+
+ // 隐藏批量生成状态
+ setTimeout(() => {
+ uiController.showBatchStatus('', false);
+ }, 3000);
+
+ // 显示最终结果
+ if (failCount === 0) {
+ utils.showNotification(`批量生成完成!成功生成 ${successCount} 张图像`, 'success');
+ } else {
+ utils.showNotification(`批量生成完成!成功 ${successCount} 张,失败 ${failCount} 张`, 'warning');
+ }
+ },
+
// 移除上传的图像
removeImage: function(imageId) {
uploadedImages = uploadedImages.filter(img => img.id !== imageId);
@@ -1338,6 +1589,7 @@ document.addEventListener('DOMContentLoaded', async () => {
// 全局函数(供HTML调用)
window.testConnection = () => app.testConnection();
window.sendMessage = () => app.sendMessage();
+window.sendBatchMessage = () => app.sendBatchMessage();
window.downloadImage = (url) => app.downloadImage(url);
window.copyImageUrl = (url) => app.copyImageUrl(url);
window.removeImage = (id) => app.removeImage(id);
diff --git a/styles.css b/styles.css
index b1d4c47..5568b01 100644
--- a/styles.css
+++ b/styles.css
@@ -460,3 +460,122 @@ body {
border-color: var(--success-color) !important;
background-color: rgba(40, 167, 69, 0.1) !important;
}
+
+/* 占位图像样式 */
+.image-placeholder {
+ position: relative;
+ border-radius: 10px;
+ overflow: hidden;
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+ transition: var(--transition);
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+ border: 2px dashed #dee2e6;
+}
+
+.image-placeholder:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
+}
+
+.image-placeholder-content {
+ width: 100%;
+ height: 200px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: #6c757d;
+}
+
+.image-placeholder-icon {
+ font-size: 3rem;
+ margin-bottom: 10px;
+ opacity: 0.5;
+}
+
+.image-placeholder-text {
+ font-size: 0.9rem;
+ text-align: center;
+ padding: 0 10px;
+}
+
+.image-placeholder-spinner {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ width: 20px;
+ height: 20px;
+ border: 2px solid #f3f3f3;
+ border-top: 2px solid var(--primary-color);
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+/* 批量生成状态指示器 */
+.batch-status {
+ position: fixed;
+ top: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: rgba(0, 0, 0, 0.8);
+ color: white;
+ padding: 10px 20px;
+ border-radius: 25px;
+ z-index: 9999;
+ display: none;
+}
+
+.batch-status.show {
+ display: block;
+ animation: slideDown 0.3s ease-out;
+}
+
+@keyframes slideDown {
+ from {
+ opacity: 0;
+ transform: translateX(-50%) translateY(-20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+ }
+}
+
+/* 图像生成模块样式 */
+.image-generation-module {
+ background: var(--light-color);
+ border-radius: 10px;
+ padding: 20px;
+ margin-bottom: 20px;
+ border: 1px solid #e9ecef;
+}
+
+.image-generation-module .input-group {
+ margin-bottom: 15px;
+}
+
+.image-generation-module .btn {
+ margin-bottom: 10px;
+}
+
+.image-generation-module .text-muted {
+ font-size: 0.85rem;
+ margin-top: 5px;
+}
+
+/* 确保按钮在移动设备上也能正确显示 */
+@media (max-width: 768px) {
+ .image-generation-module .btn {
+ padding: 10px 15px;
+ font-size: 14px;
+ }
+
+ .image-generation-module .input-group-text {
+ font-size: 14px;
+ }
+}
diff --git a/test.html b/test.html
deleted file mode 100644
index 531f218..0000000
--- a/test.html
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
-
-
-
-
OpenRouter Image Generator - 测试页面
-
-
-
-
-
-
-
-
-
-
-
-
-
- 这是测试页面,用于验证应用是否正常工作。请检查浏览器控制台是否有错误信息。
-
-
-
-
功能测试清单:
-
- -
-
- 页面加载正常
-
- -
-
- JavaScript文件加载成功
-
- -
-
- 事件监听器初始化完成
-
- -
-
- UI控制器正常工作
-
- -
-
- 文件处理功能正常
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file