refactor(web): 前端目录重构 — consoles/pages → layouts/features + shared
- consoles/admin/ → layouts/admin-layout/ - consoles/workbench/ → layouts/workbench-layout/ + features/chat/ - pages/ → features/ (dashboard, models, projects, not-found) - components/ → shared/components/ - hooks/ → shared/hooks/ - utils/ → shared/utils/ - 更新所有 import 路径 (src/web/ + tests/web/) - 更新开发文档 (README.md, frontend.md, architecture.md)
This commit is contained in:
93
src/web/features/chat/ChatPage.tsx
Normal file
93
src/web/features/chat/ChatPage.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { DeleteOutlined, MoreOutlined } from "@ant-design/icons";
|
||||
import { Conversations } from "@ant-design/x";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { App, Spin } from "antd";
|
||||
import { useState } from "react";
|
||||
|
||||
import type { Conversation } from "../../../shared/api";
|
||||
|
||||
import { useCurrentProject } from "../../layouts/workbench-layout/useCurrentProject";
|
||||
import { createConversation, deleteConversation, fetchConversations } from "../../shared/hooks/use-conversations";
|
||||
import { useModelList } from "../../shared/hooks/use-models";
|
||||
import { ChatPanel } from "./ChatPanel";
|
||||
|
||||
export function ChatPage() {
|
||||
const project = useCurrentProject();
|
||||
const [activeConversationId, setActiveConversationId] = useState<null | string>(null);
|
||||
const queryClient = useQueryClient();
|
||||
const { message } = App.useApp();
|
||||
|
||||
const CONVERSATIONS_KEY = ["conversations", project.id] as const;
|
||||
|
||||
const { data, isLoading } = useQuery({
|
||||
queryFn: () => fetchConversations(project.id),
|
||||
queryKey: CONVERSATIONS_KEY,
|
||||
});
|
||||
|
||||
const { data: modelsData } = useModelList({ pageSize: 200 });
|
||||
const textModels = (modelsData?.items ?? []).filter((m) => m.capabilities.includes("text"));
|
||||
const defaultModelId = textModels[0]?.id;
|
||||
|
||||
const deleteMutation = useMutation({
|
||||
mutationFn: (id: string) => deleteConversation(project.id, id),
|
||||
onError: (err: Error) => {
|
||||
void message.error(`删除会话失败:${err.message}`);
|
||||
},
|
||||
onSuccess: (_data: void, id: string) => {
|
||||
void queryClient.invalidateQueries({ queryKey: CONVERSATIONS_KEY });
|
||||
if (activeConversationId === id) setActiveConversationId(null);
|
||||
},
|
||||
});
|
||||
|
||||
const conversations = (data?.items ?? []).map((c: Conversation) => ({
|
||||
key: c.id,
|
||||
label: c.title,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="app-chat-page">
|
||||
<div className="app-chat-conversations">
|
||||
{isLoading ? (
|
||||
<Spin />
|
||||
) : (
|
||||
<Conversations
|
||||
activeKey={activeConversationId ?? ""}
|
||||
creation={{
|
||||
onClick: () => {
|
||||
void createConversation(project.id, defaultModelId)
|
||||
.then((conv) => {
|
||||
void queryClient.invalidateQueries({ queryKey: CONVERSATIONS_KEY });
|
||||
setActiveConversationId(conv.id);
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
void message.error(`创建会话失败:${err.message}`);
|
||||
});
|
||||
},
|
||||
}}
|
||||
items={conversations}
|
||||
menu={(conv) => ({
|
||||
items: [
|
||||
{
|
||||
danger: true,
|
||||
icon: <DeleteOutlined />,
|
||||
key: "delete",
|
||||
label: "删除",
|
||||
onClick: () => {
|
||||
deleteMutation.mutate(conv.key);
|
||||
},
|
||||
},
|
||||
],
|
||||
trigger: <MoreOutlined />,
|
||||
})}
|
||||
onActiveChange={(key) => setActiveConversationId(key)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<ChatPanel
|
||||
conversationId={activeConversationId}
|
||||
onConversationCreated={setActiveConversationId}
|
||||
projectId={project.id}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user