11 KiB
11 KiB
前端组件化梳理与规划
背景与现状
static/index.html将所有界面(配额通知、对话侧栏、文件/待办/子智能体面板、聊天区、输入区、聚焦文件、个性化抽屉、上下文菜单等)堆在一个根模板里,通过v-if/v-for直接绑定根实例的数据,缺乏可复用组件边界和样式隔离。static/index.html:35-1094static/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+ 的拆分依据。
目标与约束
- 拆分出语义明确的组件,使每个功能模块有独立的模板/逻辑/样式,降低互相影响。
- 引入现代化构建链路(Vite + Vue 3 SFC),保留当前 API/UI 行为、Socket.IO 逻辑与安全脚本(
security.js、彩蛋脚本)。 - 建立状态分层,区分“跨组件共享状态”“本地 UI 状态”“请求数据”,以 Pinia/composable 管理。
- 支持渐进式迁移:新旧模板可短期共存,确保每阶段都能运行并回归关键流程(登录→聊天→终端→上传→用量面板)。
构建与目录规划
- 构建工具:采用 Vite(支持 Vue 3、热更新、自动代码分割),后续易拓展 TypeScript/测试。
- 目录建议(均位于
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。
- 构建输出:Vite 输出到
static/dist/,Flask 模板改为加载dist/assets/*.js|css;保留 CDN 版本作为 fallback,直到迁移完成。
组件树(建议)
AppShell
├─ GlobalToasts(quota + toast 队列)
├─ ConfirmDialog
├─ EasterEggOverlay + ContextMenu + CopyCodeHandler
├─ ConversationSidebar
├─ WorkspaceLayout
│ ├─ LeftPanel
│ │ ├─ StatusHeader
│ │ ├─ PanelSwitcher
│ │ └─ PanelContent
│ │ ├─ FileTreePanel(含 FileNode)
│ │ ├─ TodoPanel
│ │ └─ SubAgentPanel
│ ├─ ChatArea
│ │ ├─ TokenDrawer
│ │ ├─ MessageList
│ │ │ ├─ MessageItem(User/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 |
对话列表、当前对话、消息流、工具状态、压缩/清空等命令;暴露 action(load/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/组件调用。
事件与数据流
- WebSocket:
io('/')监听 quota/token/status/conversation/message/easter-egg 等事件(static/app.js:769-1103),将原本直接修改data的逻辑迁移到 store action(例如conversationStore.handleAiMessageStart、resourceStore.handleQuotaUpdate)。 - REST API:
loadInitialData涵盖/api/files,/api/focused,/api/status,/api/conversations/current,/api/usage等;应抽象为apiClient,集中处理 CSRF/错误提示。 - 定时轮询:容器 0.5s、存储 5s、子智能体 5s、配额 10s(可在 store 内封装 start/stop,以路由或可见性驱动)。
- 命令通道:
socket.emit('send_command', {...})、run_command、stop_task等保持不变,只是从组件调用 store action。
迁移路线(建议)
- Phase 0 – 基础设施
- 初始化 Vite + Vue 3 + Pinia + ESLint + Prettier。
- 配置构建输出与 Flask 静态路径,写入 README 使用说明。
- Phase 1 – 壳 + Overlay
- 实现
AppShell、toast/confirm/context-menu/personalization overlay,保持旧版聊天区域引用旧模板,通过mount在#app下混用。 - 验证登录、对话加载、toast/confirm 是否正常。
- 实现
- Phase 2 – 侧栏组件
- 拆 ConversationSidebar、LeftPanel(含 FileTree/Todo/SubAgent)。
- 引入
useConversationStore、useFileStore、useTaskStore。 - 测试对话搜索/切换、文件树展开/右键、待办/子智能体展示。
- Phase 3 – ChatArea
- 拆 TokenDrawer、MessageList、InputComposer、QuickMenu、ToolMenu。
- 落地 WebSocket/消息 store,复用现有渲染逻辑(Markdown、思考块、工具卡片)。
- 回归消息流、工具调用、停止按钮、上传/设置/模式切换。
- 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,再刷新确保状态加载。 |
风险与应对
- WebSocket 事件错杀:拆分过程中如未正确解绑监听,会重复触发。→ 在
useConnectionStore中集中注册/清理,配合onBeforeUnmount。 - CSS 回归:
.sidebar,.chat-container等现有样式都位于style.css,迁移时注意命名冲突,可引入postcss-nesting+ CSS Modules,逐步拆分。 - Build/Runtime 混用:迁移初期若需要旧版
app.js支撑未拆组件,可通过 Vite 的define暴露全局函数,与 Flask 模板条件加载。 - 依赖外链:Prism/KaTeX/Marked、Socket.IO 目前从 CDN 引入。组件化后建议使用 npm 依赖,统一由 Vite 打包,避免版本漂移。
下一步
Phase 3(进行中):聊天区实时化 + 输入/工具 + Token 面板
- 连接与消息流(已完成):
useConnectionStore+useChatStore+ChatArea,加载历史、实时流式输出、发送/停止。 - 工具卡片与 Quick Menu(当前待做)
- 抽象
useToolStore管理工具分类、状态、开关(迁移toolSettings)。 - 组件化 Quick Menu(上传、工具开关、设置),接入 Pinia store。
- 渲染工具执行卡片(命令输出、文件操作等),替换 legacy DOM 结构。
- 抽象
- Token/Quota/资源面板
- 新建
useResourceStore轮询/api/container-status、/api/project-storage、/api/usage,替换 token drawer。 - 组件化
TokenDrawer,展示 Token/Quota/CPU/内存/网络/存储卡片。
- 新建
- Toast/Confirm/Context
- 搬迁
pushToast/confirmAction/contextMenu/EasterEgg overlay,形成useUiStore+GlobalToasts/ConfirmDialog组件。
- 搬迁
完成 Phase 3 后,再进入 Phase 4:聚焦面板、个性化抽屉、样式统一等。