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 @@ - +
-
对话输入
-
+
图像生成
+
- +
+
+
+ 生成数量 + +
+
+ + +
+ 支持1-10张图像同时生成
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 = ` + Generated Image +
+
+
+ + +
+
+ + +
+
+
+ `; + + // 添加事件监听器 + 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 - 测试页面 - - - - - -
-
-
-
-
-

OpenRouter Image Generator - 测试页面

-
-
-
- - 这是测试页面,用于验证应用是否正常工作。请检查浏览器控制台是否有错误信息。 -
- -
-
功能测试清单:
-
    -
  • - - 页面加载正常 -
  • -
  • - - JavaScript文件加载成功 -
  • -
  • - - 事件监听器初始化完成 -
  • -
  • - - UI控制器正常工作 -
  • -
  • - - 文件处理功能正常 -
  • -
-
- -
- - - 返回主应用 - - -
- -
-
-
-
-
-
- - - - - \ No newline at end of file