新增纯会话页面,独立路由 /pure-chat
- 新增 ChatPagePure 组件:仅保留聊天主区域(section.chat-main),去掉全局 Sidebar 和 AgentSidebar - 复用原有的 ChatHeader、ChatBody、ChatInput、ChatOutline、ChatDrawers 组件,会话功能完全一致 - 独立路由 /pure-chat 和 /pure-chat/:id,绕过 layout-shell 全局布局,不显示侧边栏 - 新增样式文件 chat-page-pure.css,适配纯会话页面全屏布局main
parent
b9cf3bc78a
commit
1b4812acae
|
|
@ -15,7 +15,8 @@ import PromptLibraryPage from './pages/PromptLibraryPage';
|
||||||
import StatsPage from './pages/StatsPage';
|
import StatsPage from './pages/StatsPage';
|
||||||
import ProfilePage from './pages/ProfilePage';
|
import ProfilePage from './pages/ProfilePage';
|
||||||
import PricingPage from './pages/PricingPage';
|
import PricingPage from './pages/PricingPage';
|
||||||
import SharedSessionPage from './pages/SharedSessionPage';
|
import SharedSessionPage from './pages/SharedSessionPage';
|
||||||
|
import ChatPagePure from './pages/chat/ChatPagePure';
|
||||||
import WorkflowsPage from './pages/WorkflowsPage';
|
import WorkflowsPage from './pages/WorkflowsPage';
|
||||||
import KnowledgeBasePage from './pages/KnowledgeBase';
|
import KnowledgeBasePage from './pages/KnowledgeBase';
|
||||||
import { useAuth } from './store/auth';
|
import { useAuth } from './store/auth';
|
||||||
|
|
@ -83,6 +84,12 @@ export default function App() {
|
||||||
<Route path="/login" element={<LoginPage />} />
|
<Route path="/login" element={<LoginPage />} />
|
||||||
<Route path="*" element={<LoginPage />} />
|
<Route path="*" element={<LoginPage />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
|
) : location.pathname.startsWith('/pure-chat') ? (
|
||||||
|
<Routes>
|
||||||
|
{/* 纯会话页:无全局 Sidebar,无 AgentSidebar,仅保留聊天主区域 */}
|
||||||
|
<Route path="/pure-chat" element={<ChatPagePure />} />
|
||||||
|
<Route path="/pure-chat/:id" element={<ChatPagePure />} />
|
||||||
|
</Routes>
|
||||||
) : (
|
) : (
|
||||||
<div className="layout-shell">
|
<div className="layout-shell">
|
||||||
{/* 只有编辑器全屏显示,其他页面均保留侧边栏 */}
|
{/* 只有编辑器全屏显示,其他页面均保留侧边栏 */}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
import { useEffect, useState, useCallback, useRef } from 'react';
|
||||||
|
import { App as AntApp, Empty } from 'antd';
|
||||||
|
import type { ChatPageLogicOutput } from './ChatPageLogic';
|
||||||
|
import { markdownToPlainText } from './utils/copy';
|
||||||
|
import { useChatPageLogic } from './ChatPageLogic';
|
||||||
|
import ChatBody from './components/ChatBody';
|
||||||
|
import ChatDrawers from './components/ChatDrawers';
|
||||||
|
import ChatHeader from './components/ChatHeader';
|
||||||
|
import ChatInput from './components/ChatInput';
|
||||||
|
import ChatOutline from './components/ChatOutline';
|
||||||
|
import type { ModelOverrides } from '../../api';
|
||||||
|
import './styles/chat-page-pure.css';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 纯会话页面组件
|
||||||
|
* 仅保留聊天主区域(section.chat-main),去掉全局 Sidebar 和 AgentSidebar(chat-side)
|
||||||
|
* 会话功能与原聊天页面完全一致
|
||||||
|
*/
|
||||||
|
export default function ChatPagePure() {
|
||||||
|
const logic = useChatPageLogic();
|
||||||
|
const { message } = AntApp.useApp();
|
||||||
|
const [outlineCollapsed, setOutlineCollapsed] = useState(true);
|
||||||
|
const isAutoScrolling = useRef(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
roomId,
|
||||||
|
highlightId,
|
||||||
|
historyDrawerOpen,
|
||||||
|
mcpDrawerOpen,
|
||||||
|
paramsDrawerOpen,
|
||||||
|
tplDrawerOpen,
|
||||||
|
agent,
|
||||||
|
agentList,
|
||||||
|
messages,
|
||||||
|
branches,
|
||||||
|
bodyRef,
|
||||||
|
sender,
|
||||||
|
navigate,
|
||||||
|
overrides,
|
||||||
|
setOverrides,
|
||||||
|
setRoomId,
|
||||||
|
setHighlightId,
|
||||||
|
setHistoryDrawerOpen,
|
||||||
|
setMcpDrawerOpen,
|
||||||
|
setParamsDrawerOpen,
|
||||||
|
setTplDrawerOpen,
|
||||||
|
handleNewSession,
|
||||||
|
} = logic;
|
||||||
|
|
||||||
|
// 初始化时,如果有历史消息,激活最后一条 Agent 消息
|
||||||
|
useEffect(() => {
|
||||||
|
if (messages.length > 0 && !highlightId) {
|
||||||
|
const agentMsgs = messages.filter(m => m.role === 'assistant' || m.role === 'agent' || m.speaker?.type === 'agent');
|
||||||
|
if (agentMsgs.length > 0) {
|
||||||
|
setHighlightId(agentMsgs[agentMsgs.length - 1].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [messages.length]);
|
||||||
|
|
||||||
|
const handleJump = useCallback((msgId: string) => {
|
||||||
|
isAutoScrolling.current = true;
|
||||||
|
setHighlightId(msgId);
|
||||||
|
const el = document.getElementById('msg-' + msgId);
|
||||||
|
if (el) {
|
||||||
|
el.scrollIntoView({ block: 'start', behavior: 'smooth' });
|
||||||
|
setTimeout(() => {
|
||||||
|
isAutoScrolling.current = false;
|
||||||
|
}, 800);
|
||||||
|
}
|
||||||
|
}, [setHighlightId]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="chat-pure-shell">
|
||||||
|
<section className="chat-main">
|
||||||
|
{!agent ? (
|
||||||
|
<div className="chat-empty-state">
|
||||||
|
<Empty description="请选择一个智能体开始对话" />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="chat-content-layout">
|
||||||
|
<div className="chat-conversation-panel">
|
||||||
|
<ChatHeader
|
||||||
|
agent={agent}
|
||||||
|
useStream={sender.useStream}
|
||||||
|
setUseStream={sender.setUseStream}
|
||||||
|
onOpenHistory={() => setHistoryDrawerOpen(true)}
|
||||||
|
onOpenParams={() => setParamsDrawerOpen(true)}
|
||||||
|
onOpenMcp={() => setMcpDrawerOpen(true)}
|
||||||
|
onManageAgent={() => navigate(`/agents/${id}`)}
|
||||||
|
onClear={sender.handleClear}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ChatBody
|
||||||
|
bodyRef={bodyRef}
|
||||||
|
agent={agent}
|
||||||
|
agentList={agentList}
|
||||||
|
currentAgentId={id!}
|
||||||
|
messages={messages}
|
||||||
|
branches={branches}
|
||||||
|
highlightId={highlightId}
|
||||||
|
sending={sender.sending}
|
||||||
|
streaming={sender.streaming}
|
||||||
|
onRegenerate={sender.handleRegenerate}
|
||||||
|
onSwitchBranch={sender.handleSwitchBranch}
|
||||||
|
scrollBottom={logic.scrollBottom}
|
||||||
|
initialScrollDoneRef={logic.initialScrollDoneRef}
|
||||||
|
onCopy={(text, mode) => {
|
||||||
|
const content = mode === 'markdown' ? text : markdownToPlainText(text);
|
||||||
|
navigator.clipboard?.writeText(content).then(() => {
|
||||||
|
message.success(mode === 'markdown' ? '已复制(Markdown)' : '已复制(纯文本)');
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ChatInput
|
||||||
|
input={sender.input}
|
||||||
|
setInput={sender.setInput}
|
||||||
|
sending={sender.sending}
|
||||||
|
attachments={sender.attachments}
|
||||||
|
setAttachments={sender.setAttachments}
|
||||||
|
imageUrls={sender.imageUrls}
|
||||||
|
setImageUrls={sender.setImageUrls}
|
||||||
|
onSend={sender.handleSend}
|
||||||
|
onStop={sender.handleStop}
|
||||||
|
onAttach={sender.handleAttach}
|
||||||
|
onOpenTpl={() => setTplDrawerOpen(true)}
|
||||||
|
modelOptions={sender.modelOptions}
|
||||||
|
activeModelValue={sender.activeModelValue}
|
||||||
|
onChangeModel={(modelId) => {
|
||||||
|
const picked = sender.modelOptions.find((o) => o.value === modelId);
|
||||||
|
setOverrides((o: ModelOverrides) => ({
|
||||||
|
...o,
|
||||||
|
model_id: modelId,
|
||||||
|
model: picked?.label ?? o.model
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
agentList={agentList}
|
||||||
|
onInsertMention={() => {}}
|
||||||
|
onOpenHistory={() => setHistoryDrawerOpen(true)}
|
||||||
|
onNewSession={handleNewSession}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ChatOutline
|
||||||
|
messages={messages}
|
||||||
|
activeId={highlightId}
|
||||||
|
collapsed={outlineCollapsed}
|
||||||
|
onToggleCollapse={() => setOutlineCollapsed(!outlineCollapsed)}
|
||||||
|
onJump={handleJump}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<ChatDrawers
|
||||||
|
agentId={id}
|
||||||
|
agent={agent}
|
||||||
|
input={sender.input}
|
||||||
|
setInput={(updater) => sender.setInput(updater)}
|
||||||
|
overrides={overrides}
|
||||||
|
setOverrides={setOverrides}
|
||||||
|
roomId={roomId}
|
||||||
|
setRoomId={setRoomId}
|
||||||
|
setHighlightId={setHighlightId}
|
||||||
|
sessionRefresh={sender.sessionRefresh}
|
||||||
|
mcpDrawerOpen={mcpDrawerOpen}
|
||||||
|
setMcpDrawerOpen={setMcpDrawerOpen}
|
||||||
|
tplDrawerOpen={tplDrawerOpen}
|
||||||
|
setTplDrawerOpen={setTplDrawerOpen}
|
||||||
|
paramsDrawerOpen={paramsDrawerOpen}
|
||||||
|
setParamsDrawerOpen={setParamsDrawerOpen}
|
||||||
|
historyDrawerOpen={historyDrawerOpen}
|
||||||
|
setHistoryDrawerOpen={setHistoryDrawerOpen}
|
||||||
|
notify={{ success: (t) => message.success(t) }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
/* 纯会话页面样式 - 无侧边栏,仅保留聊天主区域 */
|
||||||
|
|
||||||
|
.chat-pure-shell {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-pure-shell .chat-main {
|
||||||
|
flex: 1;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue