feat: 图片保存到服务器,历史记录可显示图片

This commit is contained in:
2026-04-14 10:38:59 +08:00
parent a3def9702b
commit d3e80c0afb
2 changed files with 133 additions and 17 deletions

View File

@@ -228,6 +228,28 @@
<img id="lightboxImage" src="" alt="放大图片">
</div>
<!-- 隐藏的图片上传API处理 -->
<script>
// 图片上传到服务器(保存文件)
async function uploadImageToServer(base64Data, fileName) {
try {
const response = await fetch('/api/v2/upload-image', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ image: base64Data, name: fileName })
});
const result = await response.json();
if (result.success) {
return result.path; // 返回服务器文件路径
}
return null;
} catch (e) {
console.error('图片上传失败:', e);
return null;
}
}
</script>
<!-- Markdown渲染库 -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
@@ -415,15 +437,22 @@
console.log('Processing extraData for user message:', extraData);
const bodyDiv = div.querySelector('.message-body');
// 处理图片
// 处理图片如果有服务器URL显示图片
if (extraData.images && extraData.images.length > 0) {
let imagesHtml = '<div class="history-images" style="margin-top:8px;display:flex;gap:8px;flex-wrap:wrap;">';
for (const img of extraData.images) {
// 历史记录只有图片元信息,显示占位符
imagesHtml += `<div class="history-image-placeholder" style="padding:8px 12px;background:#f0f0f0;border-radius:8px;display:flex;align-items:center;gap:6px;font-size:13px;color:#666;">
<i class="ri-image-line" style="color:#10a37f;"></i>
<span>${escapeHtml(img.name || '图片')}</span>
</div>`;
if (img.url) {
// 有服务器URL显示真实图片
imagesHtml += `<div class="history-image" style="display:inline-block;">
<img src="${img.url}" style="max-width:300px;max-height:200px;border-radius:8px;cursor:zoom-in;" onclick="openImageLightbox('${img.url}')">
</div>`;
} else {
// 没有URL显示占位符
imagesHtml += `<div class="history-image-placeholder" style="padding:8px 12px;background:#f0f0f0;border-radius:8px;display:flex;align-items:center;gap:6px;font-size:13px;color:#666;">
<i class="ri-image-line" style="color:#10a37f;"></i>
<span>${escapeHtml(img.name || '图片')}</span>
</div>`;
}
}
imagesHtml += '</div>';
if (bodyDiv) bodyDiv.insertAdjacentHTML('beforeend', imagesHtml);
@@ -893,13 +922,15 @@
lastSentFiles = files.map(f => ({
name: f.name,
type: f.type,
content: f.content
content: f.content,
serverPath: f.serverPath // 服务器路径(用于历史记录)
}));
for (const f of files) {
if (f.type.startsWith('image/')) {
// 图片直接显示
html += `<div class="uploaded-image" style="margin-bottom:8px"><img src="${f.content}" style="max-width:300px;border-radius:8px" onclick="openImageLightbox('${f.content}')"></div>`;
// 图片直接显示用服务器路径或base64
const imgSrc = f.serverPath || f.content;
html += `<div class="uploaded-image" style="margin-bottom:8px"><img src="${f.content}" style="max-width:300px;border-radius:8px" onclick="openImageLightbox('${imgSrc}')"></div>`;
} else {
// 文本文件显示名称和内容摘要
html += `<div class="uploaded-file" style="padding:8px;background:#f5f5f5;border-radius:6px;margin-bottom:8px">`;
@@ -924,7 +955,7 @@
}
// 文件上传处理
function handleFileUpload(event) {
async function handleFileUpload(event) {
const files = event.target.files;
const previewArea = document.getElementById('filePreviewArea');
@@ -933,13 +964,23 @@
// 读取文件内容
const reader = new FileReader();
reader.onload = (e) => {
reader.onload = async (e) => {
const base64Content = e.target.result;
// 图片:先上传到服务器保存
let serverPath = null;
if (file.type.startsWith('image/')) {
serverPath = await uploadImageToServer(base64Content, file.name);
console.log('图片上传结果:', serverPath);
}
const fileData = {
id: fileId,
name: file.name,
type: file.type,
size: file.size,
content: e.target.result
content: base64Content, // base64数据用于多模态模型
serverPath: serverPath // 服务器路径(用于历史记录显示)
};
pendingFiles.push(fileData);
@@ -950,8 +991,9 @@
if (file.type.startsWith('image/')) {
previewItem.classList.add('image-preview');
// 预览用本地base64显示更快
previewItem.innerHTML = `
<img src="${e.target.result}" alt="${file.name}">
<img src="${base64Content}" alt="${file.name}" style="cursor:pointer" onclick="openImageLightbox('${serverPath || base64Content}')">
<button class="file-remove" onclick="removeFile('${fileId}')"><i class="ri-close-line"></i></button>
`;
} else {