# DEV-015: Session 视图层设计
本文档描述 PLAN-029-XH-unified-session-architecture 的视图层实现:路由、
ChatPanel嵌入、chat ↔ workspace 切换。它面向前端开发者,假设读者已阅读 RFC-001 与 ADR-001。
# 1. 路由设计
# 1.1. 路由表
// packages/ui/src/router/index.ts
{
path: '/chat',
component: AppLayout,
children: [
{ path: '', redirect: '/chat/default' },
{ path: 'new', redirect: '/chat/default' },
{ path: ':sessionId', name: 'chat', component: ChatView },
],
},
{
path: '/workspace/:sessionId?',
name: 'workspace',
component: AppLayout,
children: [
{ path: '', name: 'workspace-session', component: WorkspaceView },
],
},
# 1.2. 设计决策
- 保持
/chat/:sessionId与/workspace/:sessionId并存,不统一为/session/:id。 /workspace/:sessionId?使用可选参数,兼容旧入口/workspace。- 两个路由共用
AppLayout,侧边栏与全局状态保持一致。
# 1.3. 默认首页
/ 仍然重定向到 /chat,chat 仍是用户最常入口。workspace 适合从 chat 切换进入。
# 2. 组件分层
# 2.1. ChatPanel.vue(可嵌入的对话面板)
packages/ui/src/components/chat/ChatPanel.vue
- 职责:提供消息列表 + 输入框 + SSE 流式消息。
- 接收
sessionIdprop,内部读取useChatStore/useAgentStore/useSessionStore。 - 不包含全屏布局头、不包含导航按钮。
- 上传附件时同时调用
sessionStore.addAttachment(...),把附件提升到 Session 层。
# 2.2. ChatView.vue(全屏对话视图)
packages/ui/src/components/chat/ChatView.vue
- 职责:全屏 chat 页面。
- 包含顶部标题栏(Session 标题、Agent 状态)。
- 内部嵌入
ChatPanel :session-id="currentSessionId"。 - 负责从路由参数或
currentSessionId解析当前 Session,无 Session 时自动创建。
# 2.3. WorkspaceView.vue(文件编辑 + 内嵌对话)
packages/ui/src/components/workspace/WorkspaceView.vue
- 职责:workspace 主页面。
- 左侧:文件树;中间:代码编辑器;右侧:嵌入
ChatPanel。 - 从路由参数或
currentSessionId解析当前 Session,无 Session 时自动创建。 - 当
activeFilePath变化时,调用workspaceStore.syncActiveFileToSession()把文件上下文回写 Session 层。
# 2.4. WorkspaceToolbar.vue(workspace 工具栏)
packages/ui/src/components/workspace/WorkspaceToolbar.vue
- 新增 Session 下拉选择器:切换当前 Session 并路由到
/workspace/:sessionId。 - 新增「切换回 chat」按钮:跳转到
/chat/:currentSessionId。 - 保留刷新、上传按钮。
# 2.5. Sidebar.vue(侧边栏)
packages/ui/src/components/sidebar/Sidebar.vue
- 「New Chat」按钮:创建新 Session 并跳转
/chat/:sessionId。 - Session 列表:点击后跳转
/chat/:sessionId。 - 「Workspace」按钮:跳转
/workspace/:currentSessionId;若无当前 Session,先创建。
# 3. ChatPanel 嵌入细节
# 3.1. 为什么抽取 ChatPanel
ChatView.vue包含全屏标题栏和布局逻辑,不适合直接嵌入 workspace。ChatPanel.vue只保留消息列表、输入框、SSEStream,占用空间小,可嵌入右侧面板。- 避免代码重复:ChatView 和 WorkspaceView 共用同一套消息流逻辑。
# 3.2. 嵌入布局
<!-- WorkspaceView.vue -->
<div class="flex h-full">
<div class="w-60 shrink-0 border-r"><FileTreePanel /></div>
<div class="flex-1 flex flex-col"><WorkspaceToolbar /><FileEditor /></div>
<div class="w-96 border-l flex flex-col shrink-0">
<ChatPanel :session-id="sessionId" />
</div>
</div>
当前右侧面板宽度固定为 w-96(384px)。后续可扩展为可拖拽调整宽度。
# 4. Chat ↔ Workspace 切换
# 4.1. 同一 Session 切换
所有切换入口都基于 sessionStore.currentSessionId:
- 从 chat 切换到 workspace:点击 Sidebar 的 Workspace 按钮或 WorkspaceToolbar 的返回按钮。
- 从 workspace 切换回 chat:点击 WorkspaceToolbar 的「当前 Session 标题」按钮。
# 4.2. 状态同步保证
- Session 元数据:
currentSessionId、title、context由useSessionStore统一维护。 - 消息历史:
ChatPanel始终通过chatStore.getMessages(sessionId)读取,跨视图一致。 - 附件:
sessionStore.currentSessionAttachments在两个视图中共享。 - 文件上下文:
workspaceStore.syncActiveFileToSession()把 workspace 状态写回 Session 层,chat 中可读取。
# 5. 视图层数据流
# 6. 开发约定
- 新增视图组件时,优先从
useSessionStore读取 Session 元数据,不要直接操作useChatStore的 Session 相关状态。 ChatPanel是唯一的内嵌对话组件,不要直接在其他地方嵌入ChatView。- 附件写入入口统一在
ChatPanel.handleSend;workspace 对附件只读。 - 文件上下文写入入口统一在
useWorkspaceStore.syncActiveFileToSession。
# 7. 后续可扩展点
| 扩展 | 说明 | 承接 |
|---|---|---|
| 右侧面板可拖拽宽度 | 提升 workspace 布局灵活性 | 后续 UI 改进 |
统一路由 /session/:id |
长期评估,当前保持双路由 | 未来 PLAN |
| workspace 文件拖拽到 chat | 需要附件后端支持 | PLAN-031 |
| 多 Session 并列 | 同时打开多个 workspace/chat | 未来设计 |
# 8. 参考
- RFC-001-session-domain-model.md
- ADR-001-session-store-boundary.md
- PLAN-029-XH-unified-session-architecture
最后更新: 2026-07-31 19:58:33 +0800 在 GitHub 上编辑此页