agent-Specialization/doc/frontend/legacy_ui_spec.md

184 lines
20 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.

# Legacy UI 规格说明static/old_version_backup/前端备份)
> 目的:彻底记录旧版前端(`static/old_version_backup/前端备份/index.html + app.js + style.css`)的 UI 结构、状态域、交互与 API用于后续 Phase 3+ 全量重构时精准还原体验。下文所有字段/方法名称均沿用备份代码,方便对照实现。
## 全局运行环境
- **依赖加载**:直接在 `index.html` 通过 CDN/本地脚本注入 Vue 3`Vue.createApp`、Socket.IO 客户端、Marked、Prism、KaTeX以及 `/static/security.js` 与彩蛋脚本 (`/static/easter-eggs/*.js`)。`window.requestSocketToken`、`window.ensureCsrfToken` 来自后端脚本。
- **样式体系**:单一 `style.css` 使用大量 CSS 变量(`--claude-*`打造“Claude 风”视觉;含左/右侧边栏、对话区、输入区、Toast、面板等所有样式。另挂载彩蛋专用 CSS`flood.css`/`snake.css`)。
- **入口 DOM**:整个应用被包裹在 `<div id="app">` 中,通过 Vue 模板语法渲染;根节点同时承载 Toast/Confirm/Overlay/ContextMenu。
- **脚手架行为**:页面加载时会执行 `bootstrapApp()` → 确保 Vue/Socket.IO 存在 → `createApp`,并在 `window.load` 后挂载。Viewport 逻辑通过 `updateViewportHeightVar` 挂在 `window.visualViewport` 事件CSS 使用 `--app-viewport` 控制高度。
## 状态域(`app.js` → `data()`
| 状态分组 | 关键字段 | 说明/用途 | 建议 Pinia Store |
| --- | --- | --- | --- |
| 连接 & 系统 | `isConnected`, `socket`, `projectPath`, `agentVersion`, `thinkingMode`, `stopRequested` | 管理 Socket.IO 生命周期、后端模式、思考/快速切换、Stop 指令等 | `useConnectionStore` / `useSystemStore` |
| 对话 & 消息 | `messages`, `currentConversationId`, `currentConversationTitle`, `currentMessageIndex`, `streamingMessage`, `expandedBlocks`, `thinkingScrollLocks`, `autoScrollEnabled`, `userScrolling` | 聊天历史、流式状态、思考块折叠、滚动锁、当前对话元信息 | `useConversationStore` + `useChatStore` |
| 面板布局 | `sidebarCollapsed`, `leftWidth`, `rightWidth`, `rightCollapsed`, `isResizing`, `resizingPanel`, `panelMode`, `panelMenuOpen` | 控制三个侧栏宽度/折叠及 Panel 切换 | `useUiStore` |
| 资源与统计 | `tokenPanelCollapsed`, `currentContextTokens`, `currentConversationTokens`, `usageQuota`, `usageQuotaTimer`, `projectStorage`, `containerStatus`, `containerNetRate` | Token/Quota/容器与存储统计,含轮询定时器 | `useResourceStore` |
| Toast/Confirm/Quota | `quotaToast`, `toastQueue`, `nextToastId`, `confirmDialog`, `pendingConfirmResolver` | 全局通知与确认框 | `useUiStore` |
| 文件/待办/子智能体 | `fileTree`, `expandedFolders`, `focusedFiles`, `todoList`, `subAgents`, `subAgentPollTimer` | 侧栏三合一内容、聚焦文件、子智能体轮询 | `useFileStore` / `useTaskStore` / `useSubAgentStore` |
| 工具/快捷菜单 | `toolMenuOpen`, `settingsOpen`, `quickMenuOpen`, `toolSettings`, `toolSettingsLoading`, `preparingTools`, `activeTools`, `toolActionIndex`, `toolStacks` | 工具禁用菜单、Quick Menu、流式工具卡片状态 | `useToolStore` |
| 输入与上传 | `inputMessage`, `inputLineCount`, `inputIsMultiline`, `inputIsFocused`, `uploading` | 输入框动态高度、上传反馈 | `useChatStore` / `useUploadStore` |
| 个性化 | `personalPageVisible`, `personalizationLoading`, `personalForm`, `tonePresets`, `newConsideration`, `personalizationStatus/Error` 等 | 个人空间表单、拖拽排序、开关提示 | `usePersonalizationStore` |
| 其它 | `contextMenu`, `easterEgg`, `icons`, `toolCategoryIcons`, `onDocumentClick`/`onWindowScroll`/`onKeydownListener` | 文件树右键、彩蛋生命周期、全局事件清理 | `useUiStore` |
> 注意:`toolActionIndex` 在 `data()` 中被声明两次,后者覆盖前者;重构时可合并为单一 Map。
## API & Socket 交互速览
- **REST 拉取**`/api/files`, `/api/focused`, `/api/status`, `/api/todo-list`, `/api/sub_agents`, `/api/tool-settings`, `/api/usage`, `/api/project-storage`, `/api/container-status`, `/api/conversations`, `/api/conversations/<id>/load|messages|tokens|compress`, `/api/conversations/current`, `/api/upload`, `/api/download/file|folder`, `/api/personalization`, `/api/thinking-mode`, `/api/logout`, `/api/focus` 相关(通过工具块触发),`/api/terminals`via 终端页面)。部分接口混用 GET/POST/PUT。
- **Socket 通道**`ai_message_start|end`, `thinking_start|chunk|end`, `text_start|chunk|end`, `tool_preparing|status|start|result`, `tool_settings_updated`, `append_payload`, `modify_payload`, `system_message`, `quota_update|notice|exceeded`, `token_update`, `todo_updated`, 子智能体/聚焦更新等。发送事件包括 `send_message`, `send_command`, `stop_task`
- **轮询**:容器指标每 500ms项目存储 5s额度 60s子智能体 5s仅在 tab 打开时Tool 设置按需拉取。
## 布局与模块
### 1. 对话历史侧边栏(`.conversation-sidebar`
- **收起状态**:仅露出三个纵向按钮(展开、开新对话、个人页面)。点击任意按钮会展开或进入个人页面。
- **展开后结构**
1. `conversation-header`:左侧“新建对话”主按钮、右侧“折叠”箭头;另有快捷按钮(加号、折叠/展开)。
2. `conversation-search`:输入框绑定 `searchQuery``@input` 防抖 300ms 触发 `searchConversations`(当前实现仅回退到全列表,保留 TODO
3. `conversation-list`:显示加载态/空态/列表;条目包含标题、更新时间、消息/工具数量、删除/复制按钮(调用 `/api/conversations/<id>/delete|duplicate`,逻辑位于 `methods`);点击条目触发 `loadConversation`。列表底部 `加载更多` 控制分页 (`limit=20` offset 递增)。
4. `conversation-personal-entry`:打开“个人空间”。
- **路由策略**`bootstrapRoute` 根据 `window.location.pathname` 自动加载 `conv_<id>``history.pushState` 在切换对话后更新 URL`popstate` 监听需重载历史。
### 2. 三合一左侧面板(`.left-sidebar`
1. **状态卡**:展示 Logo`iconStyle('bot')`)、`agentVersion``thinkingMode` 标签(`brain/zap` 图标切换),右侧连接状态圆点(`connection-dot`)。
2. **面板卡**
- 顶部 `panel-menu` 透视 `panelMode`files/todo/subAgents。`sidebar-view-toggle` 打开菜单,点击按钮 `selectPanelMode()` 并可 `cyclePanelMode()`
- **文件树**(默认):递归组件 `<file-node>`,使用 `expandedFolders` 记住展开;右键触发 `contextMenu`(下载文件/目录 ZIP。点击文件节点 currently 仅选中 highlight无 open 行为)。
- **待办**`todoList` 含 `instruction`, `tasks`。任务展示标题、执行人与状态标记。
- **子智能体**`subAgents` 卡片显示 `agent_id`, `status`, `summary`, `last_tool`;点击调用 `openSubAgent()` 生成 URL 并 `window.open`
3. **拖拽手柄**`.resize-handle` 左侧 `@mousedown="startResize('left', $event)"` 控制 `leftWidth`350~600px
### 3. 聊天区域(`.chat-container`
#### 3.1 Token/Quota/资源抽屉(`.token-drawer`
-`currentConversationId` 存在时显示,`tokenPanelCollapsed` 控制折叠。
- **内容**
- `Token 统计``currentContextTokens`, `currentConversationTokens`
- `性能统计`:容器状态 pill + CPU/内存 + 宿主机占位提示。
- `额度统计`:显示常规模型/思考/搜索剩余额、自动格式化 reset 时间。
- `资源统计`:网络速率(`containerNetRate`+ 项目存储用量(`projectStorage`)。
- 抽屉状态可通过 Quick Menu → 设置 → “用量统计”切换。
#### 3.2 消息时间线(`.chat-messages`
- **数据结构**`messages` 数组,元素为 `{ role: 'user'|'assistant'|'system', content, actions[] }`
- **渲染块**
1. **用户消息**:头像 + 气泡、背景框。
2. **助手消息**:每个 `action` 渲染成折叠块(`thinking`/`text`/`tool`/`append_payload`/`modify_payload`/`system`)。
- `thinking`:带“正在思考”标题,自动滚动/折叠/锁定;`thinkingScrollLocks` 确保块滚至底部,结束后 1s 自动折叠改名为“思考过程”。
- `text`Markdown 渲染 + `marked` + `Prism` + `KaTeX`,支持 `copy code``copyCodeBlock()` 通过 `data-code-id`/`data-code` 属性工作)。
- `tool`:卡片包含工具名、图标(`TOOL_ICON_MAP`),参数快照/状态消息/结果JSON、plain text、命令输出 `pre`),流式时加 loading 条;`action.tool.awaiting_content` 控制“等待正文”占位。工具 `status` 颜色区分 `preparing/running/completed/error`
- `append_payload`/`modify_payload`:专门显示文件路径、强制标志、成功/失败行数。
- `system`:用于 `role=system` 文本,折叠块 `system-message`
- **特殊处理**`renderHistoryMessages()` 会读取消息的 `reasoning_content`、自定义 metadata`append_payload`, `modify_payload`),并避免 LLM 输出的 `<<<APPEND`/`<<<MODIFY>>>` 内容直接进入 UI。
- **滚动策略**`messagesArea` 的 scroll 事件更新 `userScrolling/autoScrollEnabled``scroll-lock-toggle` 按钮切换锁定;思考块单独监听 `scroll` 以保持 pinned 行为。
#### 3.3 输入区(`.compact-input-area`
- 结构:`stadium-shell` 包含隐藏 `<input type="file">`、左侧 `+` 按钮、`textarea`、右侧发送/停止按钮。`textarea` 支持 `Ctrl+Enter` 发送、根据内容自动扩高(最多 6 行,`autoResizeInput` 计算 line-height
- `+` 按钮弹出 `quick-menu`(点击外部关闭):
- `上传文件` → 触发隐藏文件输入 → `/api/upload` → Toast 队列显示进度、完成、失败;完成后刷新文件树。
- `工具禁用` → 二级菜单罗列 `toolSettings`(按分类 toggles, icon 由 `TOOL_CATEGORY_ICON_MAP` 指定)。禁用/启用通过 POST `/api/tool-settings` 并即时刷新。
- `思考/快速模式` → 切换 `thinkingMode`(调用 `/api/thinking-mode`)。
- `设置` 二级菜单:
1. `实时终端``openRealtimeTerminal()` 新开 `/terminal`
2. `聚焦面板` → 切换右侧 `rightCollapsed`
3. `用量统计` → 切换 Token Drawer。
4. `压缩对话` → POST `/api/conversations/<id>/compress`,需确认框、`compressing` 状态。
- 发送按钮:若 `streamingMessage` 为真则显示 STOP 图标,点击调用 `stopTask`Socket `stop_task`)。发送前检查额度(`isQuotaExceeded` + `quotaToast`)。命令以 `/` 开头时走 `send_command`
### 4. 右侧聚焦面板(`.right-sidebar`
- 默认折叠(`rightCollapsed = true`),通过 Quick Menu → 设置或拖拽手柄展开。
- 内容:顶部标题 + “聚焦文件 (x/3)” 计数;`focusedFiles` 为 `{ path: { size, content } }`
- 每个 tab 展示文件名、大小KB, 1 decimal、`<pre><code>` 语法高亮(`getLanguageClass` 基于拓展名)。无文件时显示“暂无聚焦文件”。
### 5. 个人空间(`.personal-page-overlay`
- 从左侧最下方“个人页面”按钮或 Sidebar collapsed 图标进入,覆盖全屏(透明蒙层 + Card。支持鼠标/触摸长按关闭(`handleOverlayPress*`)。
- 表单字段:启用开关(即时 POST `/api/personalization``personalizationToggleUpdating` 防抖、自称、称呼、职业、语气、Considerations 列表(拖拽排序 + 新增输入 + 预设语气 chips。保存按钮提交 `/api/personalization`POST JSON
- 顶部按钮退出登录POST `/logout`)与返回工作区。
### 6. 全局 Overlay/服务
- **Quota Toast**:置顶横幅 `quota-toast` 显示额度提醒;`showQuotaToast()` 控制。
- **Toast Stack**`toastQueue` 通过 `<transition-group>` 渲染,支持自动消失/手动关闭。
- **Confirm Dialog**`confirmDialog` + `handleConfirm` 用于危险操作。
- **上下文菜单**`contextMenu` 仅针对文件树节点(下载文件/文件夹)。
- **Easter Egg Overlay**`easterEgg.active` 控制 `<div class="easter-egg-overlay">`Tool `trigger_easter_egg` 结果由 `handleEasterEggPayload` -> `EasterEggRegistry` 播放,支持自动清理。
## 消息/工具渲染细节
- **助手消息结构**`ensureAssistantMessage()` 保证 `messages` 末尾存在 `role: 'assistant'``actions: []`,之后所有流式事件都向该 `actions` push。
- **流式顺序**`ai_message_start` 新增消息 → `thinking_start/chunk/end``text_start/chunk/end` → 多个工具事件preparing/status/start/result/append_payload/modify_payload/system_message`ai_message_end`(重置 `currentMessageIndex`, `streamingMessage`, `stopRequested`)。
- **Tool Action**`action.tool` 包含 `id/name/status/statusDetail/result/arguments/argumentSnapshot/argumentLabel/message/executionId/awaiting_content`。`registerToolAction` & Maps 用于后续 socket事件匹配。
- **Append/Modify Payload**:用于 `append_to_file`/`modify_file` 工具响应,展示 path、强制写入 flag、影响行数/块数。
- **System Block**`appendSystemAction` 插入“系统消息” collapsible。
- **LaTeX**`renderLatexInRealtime()` 在 `text_chunk`/`text_end` 之后执行 `renderMathInElement`
## 文件/待办/聚焦/子智能体逻辑
- **文件树**`updateFileTree()` 将 `/api/files` 返回的嵌套结构转换为 nodes`{ type: 'folder'|'file', name, path, children, annotation }`);右键 `@contextmenu` 记录 node 与鼠标位置,点击菜单按钮调用 `/api/download/file|folder`
- **聚焦文件**`/api/focused` 返回 { path -> { size, content } },显示/下载/滚动 purely 只读。工具 `focus_file/unfocus_file` 事件会触发 `focusedFiles` 刷新(`applyStatusSnapshot`/socket
- **待办**`/api/todo-list` -> `this.todoList = { tasks: [], instruction }``todo_updated` socket 事件使 UI 立即同步。
- **子智能体**`/api/sub_agents` + 5s 轮询;`openSubAgent` 构建 URL优先 `window.SUB_AGENT_BASE_URL`。状态 pill 颜色由 class `agent.status` 控制。
## Token/资源/Quota 面板行为
- **token_update socket**:仅处理当前对话 ID一次更新 `currentConversationTokens` + `currentContextTokens` + `usageQuota` + `quotaToast`
- **工具完成数**`updateCurrentContextTokens()` 在 Tool 完成/消息发送后延迟调用 `/api/conversations/<id>/tokens`
- **容器指标**`pollContainerStats()`(未在片段展示)调用 `/api/container-status``updateContainerStatus()` 根据 `stats.timestamp/rx_bytes/tx_bytes` 计算 `containerNetRate`(字节差 / 时间差)。
- **项目存储**`pollProjectStorage()` -> `/api/project-storage``usage_percent`/`limit_label` 直接展示。
- **额度**`/api/usage` -> `normalizeUsageQuota()` -> Quick Menu, Toast, Token Drawer 共享;`quota_notice/exceeded` socket 触发顶部通知 + 立刻刷新额度。
## 快捷交互流程
1. **加载流程**`mounted` → `bootstrapRoute()`(解析 URL`initSocket()`(分配 token, 监听事件)→ `initScrollListener()``setTimeout(loadInitialData, 500)`(并发加载文件树/聚焦/待办/状态/工具设置/对话 tokens`start*Polling()`
2. **发送消息**:输入→`sendMessage()` 检查 quota → push 用户消息 → `socket.emit('send_message', { message, conversation_id })``scrollToBottom` → 1s 后刷新 token。
3. **停止任务**`streamingMessage` + Stop 按钮 → `socket.emit('stop_task')`。`ai_message_end` 或 `text_end` 事件最终 `stopRequested = false`
4. **上传**Quick Menu “上传文件” → `<input type=file>``/api/upload`FormData→ Toast 过渡 + `refreshFileTree()` → 出错时匹配错误文案(安全审核/禁用类型)。
5. **对话切换**:侧栏点击 → `/api/conversations/<id>/load`PUT`resetAllStates()``fetchAndDisplayHistory()` + `fetchConversationTokenStatistics()` + `updateCurrentContextTokens()``history.pushState()`
6. **个性化**:打开个人空间 → `/api/personalization` GET → 表单编辑/拖拽/预设 → 保存 POST → 成功/失败提示;启用/停用走单独 API。
7. **工具禁用**Quick Menu → Tool submenu → POST `/api/tool-settings` → UI 更新 + `tool_settings_updated` socket 兜底。
8. **压缩对话**Quick Menu → 设置 → `handleCompressConversationClick()` → Confirm → POST `/api/conversations/<id>/compress` → 新 ID 赋值 + 继续加载。
## 样式与布局要点
- **定位**`.main-container` 高度锁定 `var(--app-viewport)`避免移动端地址栏影响body `overflow: hidden`,聊天区域内部 `overflow-y: auto`
- **配色**:大量 `var(--claude-*)` 变量 + 玻璃态背景(`backdrop-filter`)。按钮/输入/面板 radius 取值 12~24px。
- **动效**:多处 `transition` (`quick-menu`, `submenu-slide`, `personal-page-fade`, `quota-toast-fade`、`mode-icon` 等)Thinking → Collapse, Scroll lock UI 2 态 SVG。
- **拖拽**Considerations 列表使用 `draggable + dragstart/dragover/drop`;侧栏手柄 `cursor: col-resize`
- **Icon 渲染**:统一使用 CSS mask`.icon`+ `iconStyle('--icon-src')` 设定路径。
## 重构建议(旧 → 新 Store/组件映射)
| 模块 | 旧 DOM/方法 | 目标组件 | 相关 Store/Composable |
| --- | --- | --- | --- |
| 对话历史侧栏 | `conversation-sidebar` + `loadConversationsList/loadConversation/duplicate/delete` | `ConversationSidebar.vue` | `useConversationStore` |
| Logo/状态卡 + Panel 切换 | `.sidebar-status` + `.sidebar-panel-card` | `LeftPanel.vue` + `StatusHeader.vue` + `PanelSwitcher.vue` | `useSystemStore`, `useFileStore`, `useTaskStore`, `useSubAgentStore` |
| 文件树节点 | `<file-node>` 组件 | `FileTreePanel.vue` | `useFileStore` |
| Token/Quota Drawer | `.token-drawer` + `startContainerStatsPolling` 等 | `TokenDrawer.vue` + `ResourceStats.vue` | `useResourceStore` |
| 聊天消息 | `.chat-messages` + `messages/actions` 渲染 | `ChatArea.vue` + `MessageList.vue` + `MessageItem.vue` + `ActionCard` 子组件 | `useChatStore`, `useToolStore` |
| 输入区/Quick Menu | `.compact-input-area` + `quick-menu` | `InputComposer.vue` + `QuickMenu.vue` + `ToolToggleMenu.vue` + `SettingsMenu.vue` | `useChatStore`, `useToolStore`, `useUploadStore` |
| 聚焦面板 | `.right-sidebar` | `RightFocusPanel.vue` | `useFocusStore` |
| 个人空间 | `.personal-page-overlay` | `PersonalizationDrawer.vue` | `usePersonalizationStore` |
| Toast/Confirm/ContextMenu | `quota-toast`, `.toast-stack`, `.confirm-overlay`, `.context-menu` | `ToastStack.vue` + `ConfirmDialog.vue` + `ContextMenu.vue` | `useUiStore` |
| 彩蛋 | `.easter-egg-overlay` + `handleEasterEggPayload` | `EasterEggOverlay.vue` + composable | `useUiStore` |
## 关键注意事项
- **完全还原**Phase 标签已失效,重构时应以本文 + 备份代码为唯一真值;任何现存 Vite 代码若偏离需求可直接推翻。
- **流式同步**Tool/思考/文本事件严格依赖顺序、状态映射与 `action.id`,必须在组件化后保持同等粒度,避免“危房式”拼接。
- **多重状态同步**Token 面板、Quota Toast、Quick Menu 与资源轮询之间互相引用(如工具完成后更新 Token实现时应通过跨 store action 协调。
- **可访问性**:旧版所有按钮均提供 `title/aria-label`,复制按钮状态 2s 自动恢复;滚动锁按钮使用 `svg` icon 反馈;保留这些交互细节。
- **安全脚本**`/static/security.js`、`window.ensureCsrfToken`、`window.requestSocketToken`、`EasterEggRegistry` 等全局依赖需要在新构建链路中继续注入或以 shim 方式提供。
> 后续编码时,请以此文档 + `static/old_version_backup/前端备份` 中的 HTML/CSS/JS 为参考基准,确保界面结构、逻辑流与交互表现与旧版完全一致,再逐步拆分到 Vue 组件与 Pinia store。