agent-Specialization/doc/frontend/component_plan.md

149 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 前端组件化梳理与规划
## 背景与现状
- `static/index.html` 将所有界面(配额通知、对话侧栏、文件/待办/子智能体面板、聊天区、输入区、聚焦文件、个性化抽屉、上下文菜单等)堆在一个根模板里,通过 `v-if`/`v-for` 直接绑定根实例的数据,缺乏可复用组件边界和样式隔离。`static/index.html:35-1094`
- `static/app.js` 中单个 `createApp` 承担了连接管理、消息流、文件树、资源监控、使用额度、工具控制、上传、个性化设置、彩蛋等所有状态/方法,数据段跨越 150+ 行,方法 200+ 个,总体约 4.4k 行,导致维护和测试困难。`static/app.js:186-4362`
- 现有代码依赖 Vue CDN全局变量`ICONS`、`TOOL_CATEGORY_ICON_MAP`、`window.requestSocketToken` 等)直接注入;没有构建步骤,也就无法按模块拆分或使用 TypeScript/ESM。
> ✅ Phase 1脚手架 + 入口切换)已落地,过程总结见 `doc/frontend/phase1_setup.md`。
> ✅ Phase 2对话侧栏 + 文件面板)已上线,详见 `doc/frontend/phase2_sidebar.md`。
> 以下规划作为 Phase 3+ 的拆分依据。
## 目标与约束
1. 拆分出语义明确的组件,使每个功能模块有独立的模板/逻辑/样式,降低互相影响。
2. 引入现代化构建链路Vite + Vue 3 SFC保留当前 API/UI 行为、Socket.IO 逻辑与安全脚本(`security.js`、彩蛋脚本)。
3. 建立状态分层,区分“跨组件共享状态”“本地 UI 状态”“请求数据”,以 Pinia/composable 管理。
4. 支持渐进式迁移:新旧模板可短期共存,确保每阶段都能运行并回归关键流程(登录→聊天→终端→上传→用量面板)。
## 构建与目录规划
1. **构建工具**:采用 Vite支持 Vue 3、热更新、自动代码分割后续易拓展 TypeScript/测试。
2. **目录建议**(均位于 `static/` 下):
- `src/main.ts`:入口,挂载 `App.vue`、注入 Pinia、注册全局指令/组件。
- `src/App.vue`:根壳组件,只负责大布局与全局 overlay 容器。
- `src/components/`:按功能域组织(如 `chat/`, `sidebar/`, `panels/`, `overlays/`, `common/`)。
- `src/stores/`Pinia store`useConnectionStore`, `useConversationStore`, `useResourceStore`, `useFileStore`, `useUiStore`, `usePersonalizationStore`)。
- `src/composables/`WebSocket 管理、消息流解析、Toast/Confirm service、复制代码块等工具。
- `src/assets/`:静态 SVG/样式;继续复用 `style.css`,逐步拆为 `src/styles/`
- `src/utils/request.ts`:封装带 CSRF 的 fetch。
3. **构建输出**Vite 输出到 `static/dist/`Flask 模板改为加载 `dist/assets/*.js|css`;保留 CDN 版本作为 fallback直到迁移完成。
## 组件树(建议)
```
AppShell
├─ GlobalToastsquota + toast 队列)
├─ ConfirmDialog
├─ EasterEggOverlay + ContextMenu + CopyCodeHandler
├─ ConversationSidebar
├─ WorkspaceLayout
│ ├─ LeftPanel
│ │ ├─ StatusHeader
│ │ ├─ PanelSwitcher
│ │ └─ PanelContent
│ │ ├─ FileTreePanel含 FileNode
│ │ ├─ TodoPanel
│ │ └─ SubAgentPanel
│ ├─ ChatArea
│ │ ├─ TokenDrawer
│ │ ├─ MessageList
│ │ │ ├─ MessageItemUser/Assistant/System
│ │ │ └─ ToolAction / ThinkingBlock / MarkdownBlock
│ │ ├─ ScrollLockToggle
│ │ └─ InputComposer
│ │ ├─ QuickMenu
│ │ │ ├─ ToolToggleMenu
│ │ │ └─ SettingsMenu
│ │ └─ AttachmentButton / ModeSwitch
│ └─ RightFocusPanel
└─ PersonalizationDrawer
```
说明:
- ConversationSidebar 负责搜索/分页/对话操作,接收 `conversations`, `currentConversationId`、触发 `loadConversation/delete/duplicate`。`static/index.html:91-204`
- LeftPanel 根据 `panelMode` 动态渲染文件树(`fileTree`, `expandedFolders`)、待办(`todoList`)、子智能体(`subAgents`)。`static/index.html:217-368`
- ChatArea 内部组件拆分消息渲染、Token/资源卡片、输入框及快捷菜单。`static/index.html:374-820`
- RightFocusPanel 只观察 `focusedFiles`,提供 tabs 和 `downloadFile` 操作。`static/index.html:906-958`
- PersonalizationDrawer 独立组件管理表单、拖拽排序与保存逻辑。`static/index.html:959-1094`
- Toasts/Confirm/ContextMenu/EasterEgg 形成 `overlays/` 组件,避免根实例直接绑定。
## 状态域与 Store 设计
| Store/Composable | 职责 | 关键数据来源 |
| --- | --- | --- |
| `useConnectionStore` | 维护 Socket.IO 实例、连接状态、stop 请求、服务器状态快照;统一事件监听与销毁。| `initSocket` 逻辑 `static/app.js:711-1103` |
| `useConversationStore` | 对话列表、当前对话、消息流、工具状态、压缩/清空等命令;暴露 actionload/create/delete/duplicate/send/compress。| `loadConversationsList`、`loadConversation`、`fetchAndDisplayHistory`、消息 handlers `static/app.js:1904-3336` |
| `useResourceStore` | Token 统计、容器状态、网络/存储、配额轮询;提供格式化工具。| `loadInitialData`、`updateContainerStatus`、`pollContainerStats`、`fetchUsageQuota` `static/app.js:1595-1870` |
| `useFileStore` | 文件树、聚焦文件、右键菜单、下载逻辑。| `updateFileTree`、`downloadFile/Folder` `static/app.js:615-707`、`static/index.html:906-958` |
| `useTaskStore` | 待办列表、子智能体轮询。| `fetchSubAgents`, `fetchTodoList` `static/app.js:2885-2938` |
| `useUploadStore` | 上传状态、toast 更新、复用安全扫描提示。| `uploadSelectedFile` `static/app.js:2940-3108` |
| `usePersonalizationStore` | 个人页表单、保存/启停逻辑。| `openPersonalPage`~`savePersonalization` `static/app.js:2496-2669` |
| `useUiStore` | 侧栏折叠、面板宽度、QuickMenu/ToolMenu/Settings、toast 队列、confirm/overlay。| `data` 中的 UI 字段 `static/app.js:224-360` + `pushToast/confirmAction` `static/app.js:4200-4334` |
Store 之间通过 action 通信,如 `conversationStore` 发出 `loadConversation` 后通知 `resourceStore` 更新 token`uiStore` 暴露 toast/confirm 服务供其他 store/组件调用。
## 事件与数据流
1. **WebSocket**`io('/')` 监听 quota/token/status/conversation/message/easter-egg 等事件(`static/app.js:769-1103`),将原本直接修改 `data` 的逻辑迁移到 store action例如 `conversationStore.handleAiMessageStart`、`resourceStore.handleQuotaUpdate`)。
2. **REST API**`loadInitialData` 涵盖 `/api/files`, `/api/focused`, `/api/status`, `/api/conversations/current`, `/api/usage` 等;应抽象为 `apiClient`,集中处理 CSRF/错误提示。
3. **定时轮询**:容器 0.5s、存储 5s、子智能体 5s、配额 10s可在 store 内封装 start/stop以路由或可见性驱动
4. **命令通道**`socket.emit('send_command', {...})`、`run_command`、`stop_task` 等保持不变,只是从组件调用 store action。
## 迁移路线(建议)
1. **Phase 0 基础设施**
- 初始化 Vite + Vue 3 + Pinia + ESLint + Prettier。
- 配置构建输出与 Flask 静态路径,写入 README 使用说明。
2. **Phase 1 壳 + Overlay**
- 实现 `AppShell`、toast/confirm/context-menu/personalization overlay保持旧版聊天区域引用旧模板通过 `mount``#app` 下混用。
- 验证登录、对话加载、toast/confirm 是否正常。
3. **Phase 2 侧栏组件**
- 拆 ConversationSidebar、LeftPanel含 FileTree/Todo/SubAgent
- 引入 `useConversationStore`、`useFileStore`、`useTaskStore`。
- 测试对话搜索/切换、文件树展开/右键、待办/子智能体展示。
4. **Phase 3 ChatArea**
- 拆 TokenDrawer、MessageList、InputComposer、QuickMenu、ToolMenu。
- 落地 WebSocket/消息 store复用现有渲染逻辑Markdown、思考块、工具卡片
- 回归消息流、工具调用、停止按钮、上传/设置/模式切换。
5. **Phase 4 RightPanel & Personalization**
- 拆聚焦文件与个人页组件,接入 `usePersonalizationStore`
- 完成 CSS 抽取,移除旧版 `static/app.js`/`index.html`,保留必要 polyfill。
每个阶段都保持 `main.py`/`web_server.py` 无需改动,仅替换静态入口文件即可。
## 测试与验证
| 阶段 | 核心验证 | 自动化建议 |
| --- | --- | --- |
| Phase 0 | `npm run dev/build` 正常Flask 引用 `dist`;加载页可看到“正在连接服务器”。 | 添加 `npm run lint`、`npm run typecheck`(若启用 TS。 |
| Phase 1 | Toast/Confirm/上下文菜单、彩蛋覆盖层可交互;连接断开/重连提示正常。 | 编写 Vitest 针对 toast store 的单测。 |
| Phase 2 | 对话 CRUD、文件树右键下载、待办/子智能体轮询无误;侧栏拖拽宽度保持。 | Playwright 脚本:创建/切换/删除对话,校验 API 调用。 |
| Phase 3 | 消息流畅、工具卡片渲染、上传扫描提示、快捷菜单/设置工作。 | 录制 `socket` mock用 Jest/Vitest 验证消息 reducer。 |
| Phase 4 | 聚焦文件显示、个人化表单保存;整体构建包大小可控。 | e2e提交 personalization再刷新确保状态加载。 |
## 风险与应对
1. **WebSocket 事件错杀**:拆分过程中如未正确解绑监听,会重复触发。→ 在 `useConnectionStore` 中集中注册/清理,配合 `onBeforeUnmount`
2. **CSS 回归**`.sidebar`, `.chat-container` 等现有样式都位于 `style.css`,迁移时注意命名冲突,可引入 `postcss-nesting` + CSS Modules逐步拆分。
3. **Build/Runtime 混用**:迁移初期若需要旧版 `app.js` 支撑未拆组件,可通过 Vite 的 `define` 暴露全局函数,与 Flask 模板条件加载。
4. **依赖外链**Prism/KaTeX/Marked、Socket.IO 目前从 CDN 引入。组件化后建议使用 npm 依赖,统一由 Vite 打包,避免版本漂移。
## 下一步
Phase 3进行中聊天区实时化 + 输入/工具 + Token 面板
1. **连接与消息流(已完成)**`useConnectionStore` + `useChatStore` + `ChatArea`,加载历史、实时流式输出、发送/停止。
2. **工具卡片与 Quick Menu**(当前待做)
- 抽象 `useToolStore` 管理工具分类、状态、开关(迁移 `toolSettings`)。
- 组件化 Quick Menu上传、工具开关、设置接入 Pinia store。
- 渲染工具执行卡片(命令输出、文件操作等),替换 legacy DOM 结构。
3. **Token/Quota/资源面板**
- 新建 `useResourceStore` 轮询 `/api/container-status`、`/api/project-storage`、`/api/usage`,替换 token drawer。
- 组件化 `TokenDrawer`,展示 Token/Quota/CPU/内存/网络/存储卡片。
4. **Toast/Confirm/Context**
- 搬迁 `pushToast/confirmAction/contextMenu`/EasterEgg overlay形成 `useUiStore` + `GlobalToasts/ConfirmDialog` 组件。
完成 Phase 3 后,再进入 Phase 4聚焦面板、个性化抽屉、样式统一等。