feat: 支持多图像上传和预览

This commit is contained in:
2025-09-04 08:56:00 +08:00
parent 37a31f7264
commit 72f9666421
2 changed files with 37 additions and 21 deletions

View File

@@ -88,19 +88,21 @@
<div class="mb-4">
<h5><i class="fas fa-upload me-2"></i>上传参考图像</h5>
<div class="row">
<div class="col-md-6">
<div class="col-md-4">
<div class="border-2 border-dashed rounded p-4 text-center h-100 d-flex flex-column justify-content-center" id="dropZone">
<i class="fas fa-cloud-upload-alt fa-3x text-muted mb-3"></i>
<p class="text-muted">拖拽图像到此处或点击选择文件</p>
<input type="file" class="d-none" id="imageInput" accept="image/*">
<p class="text-muted">拖拽图像到此处或点击选择文件 (最多10张)</p>
<input type="file" class="d-none" id="imageInput" accept="image/*" multiple>
<button class="btn btn-outline-primary" onclick="document.getElementById('imageInput').click()">
选择图像
</button>
</div>
</div>
<div class="col-md-6">
<div id="imagePreview" class="h-100 d-flex align-items-center justify-content-center">
<p class="text-muted">未选择图像</p>
<div class="col-md-8">
<div class="row" id="imagePreview" style="max-height: 250px; overflow-y: auto; border: 1px solid #dee2e6; border-radius: .25rem; padding-top: 1rem;">
<div class="col-12 d-flex h-100 align-items-center justify-content-center">
<p class="text-muted">未选择图像</p>
</div>
</div>
</div>
</div>

View File

@@ -17,7 +17,7 @@ let currentModalInstance = null; // 当前模态框实例
// 配置常量
const CONFIG = {
MAX_FILE_SIZE: 10485760, // 10MB
MAX_FILES_PER_UPLOAD: 1, // 限制为只上传一张图片
MAX_FILES_PER_UPLOAD: 10, // 限制为最多上传10张图片
SUPPORTED_IMAGE_FORMATS: ['image/jpeg', 'image/png', 'image/gif', 'image/webp'],
MAX_CHAT_HISTORY: 50, // 减少聊天历史记录数量以节省存储空间
MAX_GENERATED_IMAGES: 20, // 减少存储的图像数量以防止存储空间溢出
@@ -718,7 +718,8 @@ const apiService = {
const payload = {
model: settings.model,
messages: messages,
stream: false
stream: false,
"modalities": ["image","text"]
};
const controller = new AbortController();
@@ -1485,6 +1486,10 @@ const uiController = {
// 显示图像预览
displayImagePreview: function(imageData) {
const preview = document.getElementById('imagePreview');
const placeholderContainer = preview.querySelector('.col-12.d-flex');
if (placeholderContainer) {
placeholderContainer.remove();
}
// 确保图像数据是Blob URL用于显示但保持原始数据用于其他操作
let displayUrl;
@@ -1498,19 +1503,25 @@ const uiController = {
displayUrl = imageData.data;
}
preview.innerHTML = `
<div class="card h-100">
<img src="${displayUrl}" class="card-img-top image-preview h-75" alt="${imageData.name}" loading="lazy" style="object-fit: contain;">
const wrapper = document.createElement('div');
wrapper.className = 'col-md-4 mb-3';
wrapper.dataset.imageId = imageData.id; // Store imageId here
wrapper.innerHTML = `
<div class="card h-100 uploaded-image-card">
<img src="${displayUrl}" class="card-img-top image-preview" alt="${imageData.name}" loading="lazy" style="object-fit: contain; height: 100px;">
<div class="card-body p-2">
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">${utils.formatFileSize(imageData.size)}</small>
<small class="text-muted text-truncate" title="${imageData.name}">${imageData.name}</small>
<button class="btn btn-sm btn-outline-danger" onclick="app.removeImage(${imageData.id})" title="删除">
<i class="fas fa-trash"></i>
</button>
</div>
<small class="text-muted">${utils.formatFileSize(imageData.size)}</small>
</div>
</div>
`;
preview.appendChild(wrapper);
},
// 保存聊天历史 - 新增消息时调用
@@ -1783,11 +1794,12 @@ const fileHandler = {
// 处理文件
handleFiles: function(files) {
const preview = document.getElementById('imagePreview');
preview.innerHTML = '';
// 限制文件数量
const filesToProcess = Array.from(files).slice(0, CONFIG.MAX_FILES_PER_UPLOAD);
if (uploadedImages.length + files.length > CONFIG.MAX_FILES_PER_UPLOAD) {
utils.showNotification(`最多只能上传 ${CONFIG.MAX_FILES_PER_UPLOAD} 张图片。`, 'warning');
return;
}
const filesToProcess = Array.from(files);
filesToProcess.forEach(file => {
try {
@@ -2123,11 +2135,13 @@ const app = {
removeImage: function(imageId) {
uploadedImages = uploadedImages.filter(img => img.id !== imageId);
const preview = document.getElementById('imagePreview');
const imageElement = preview.querySelector(`[data-image-id="${imageId}"]`);
if (imageElement) {
imageElement.remove();
}
if (uploadedImages.length === 0) {
preview.innerHTML = '<p class="text-muted">未选择图像</p>';
} else {
preview.innerHTML = '';
uploadedImages.forEach(img => uiController.displayImagePreview(img));
preview.innerHTML = '<div class="col-12 d-flex h-100 align-items-center justify-content-center"><p class="text-muted">未选择图像</p></div>';
}
},