feat(页面): 聊天页面集成文件上传功能和动画样式
聊天页面更新: - handleSend 方法扩展支持文件参数 - 将上传的文件转换为 sendMessage 所需格式 - 从数据库加载历史消息的上传图片和文档 - MessageBubble 组件传递 uploadedImages 和 uploadedDocuments 全局样式更新: - 添加 fadeInFast 和 fadeOutFast 淡入淡出动画 - 添加 scaleInFast 缩放动画 - 用于模态框和灯箱的平滑过渡效果
This commit is contained in:
parent
4cb3f162e3
commit
cb86380e7f
@ -11,6 +11,7 @@ import { useConversation, useConversations } from '@/hooks/useConversations';
|
|||||||
import { useStreamChat, type ChatMessage } from '@/hooks/useStreamChat';
|
import { useStreamChat, type ChatMessage } from '@/hooks/useStreamChat';
|
||||||
import { useModels, useTools, useSettings } from '@/hooks/useSettings';
|
import { useModels, useTools, useSettings } from '@/hooks/useSettings';
|
||||||
import { useAuth } from '@/providers/AuthProvider';
|
import { useAuth } from '@/providers/AuthProvider';
|
||||||
|
import type { UploadFile } from '@/types/file-upload';
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
params: Promise<{ id: string }>;
|
params: Promise<{ id: string }>;
|
||||||
@ -75,8 +76,12 @@ export default function ChatPage({ params }: PageProps) {
|
|||||||
status: 'completed' as const,
|
status: 'completed' as const,
|
||||||
inputTokens: msg.inputTokens || undefined,
|
inputTokens: msg.inputTokens || undefined,
|
||||||
outputTokens: msg.outputTokens || undefined,
|
outputTokens: msg.outputTokens || undefined,
|
||||||
// 从数据库加载图片数据
|
// 从数据库加载图片数据(代码执行产生的)
|
||||||
images: (msg.images as string[]) || undefined,
|
images: (msg.images as string[]) || undefined,
|
||||||
|
// 从数据库加载用户上传的图片
|
||||||
|
uploadedImages: (msg.uploadedImages as string[]) || undefined,
|
||||||
|
// 从数据库加载用户上传的文档
|
||||||
|
uploadedDocuments: (msg.uploadedDocuments as { name: string; size: number; type: string; content: string }[]) || undefined,
|
||||||
}));
|
}));
|
||||||
setInitialMessages(historyMessages);
|
setInitialMessages(historyMessages);
|
||||||
}
|
}
|
||||||
@ -214,7 +219,7 @@ export default function ChatPage({ params }: PageProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息
|
||||||
const handleSend = async (message: string) => {
|
const handleSend = async (message: string, files?: UploadFile[]) => {
|
||||||
let targetConversationId = chatId;
|
let targetConversationId = chatId;
|
||||||
|
|
||||||
// 如果是新对话,先创建对话
|
// 如果是新对话,先创建对话
|
||||||
@ -236,12 +241,20 @@ export default function ChatPage({ params }: PageProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 准备文件信息给 sendMessage
|
||||||
|
const uploadedFiles = files?.map(f => ({
|
||||||
|
file: f.file,
|
||||||
|
type: f.type,
|
||||||
|
previewUrl: f.previewUrl,
|
||||||
|
}));
|
||||||
|
|
||||||
await sendMessage({
|
await sendMessage({
|
||||||
conversationId: targetConversationId,
|
conversationId: targetConversationId,
|
||||||
message,
|
message,
|
||||||
model: selectedModelId,
|
model: selectedModelId,
|
||||||
tools: enabledTools,
|
tools: enabledTools,
|
||||||
enableThinking,
|
enableThinking,
|
||||||
|
files: uploadedFiles,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -438,6 +451,8 @@ export default function ChatPage({ params }: PageProps) {
|
|||||||
isStreaming={message.status === 'streaming'}
|
isStreaming={message.status === 'streaming'}
|
||||||
error={message.error}
|
error={message.error}
|
||||||
images={message.images}
|
images={message.images}
|
||||||
|
uploadedImages={message.uploadedImages}
|
||||||
|
uploadedDocuments={message.uploadedDocuments}
|
||||||
pyodideStatus={message.pyodideStatus}
|
pyodideStatus={message.pyodideStatus}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|||||||
@ -224,6 +224,40 @@ body {
|
|||||||
animation: popUp 0.15s ease-out;
|
animation: popUp 0.15s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Modal 动画 */
|
||||||
|
@keyframes fadeInFast {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeOutFast {
|
||||||
|
from { opacity: 1; }
|
||||||
|
to { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes scaleInFast {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-in-fast {
|
||||||
|
animation: fadeInFast 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-fade-out-fast {
|
||||||
|
animation: fadeOutFast 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-scale-in-fast {
|
||||||
|
animation: scaleInFast 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================================
|
/* ========================================
|
||||||
响应式设计
|
响应式设计
|
||||||
======================================== */
|
======================================== */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user