# 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**:整个应用被包裹在 `
` 中,通过 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/
/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//delete|duplicate`,逻辑位于 `methods`);点击条目触发 `loadConversation`。列表底部 `加载更多` 控制分页 (`limit=20` offset 递增)。
4. `conversation-personal-entry`:打开“个人空间”。
- **路由策略**:`bootstrapRoute` 根据 `window.location.pathname` 自动加载 `conv_`,`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()`。
- **文件树**(默认):递归组件 ``,使用 `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()` 会解析 `` 块、自定义 metadata(`append_payload`, `modify_payload`),并避免 LLm 输出的 `<<>>` 内容直接进入 UI。
- **滚动策略**:`messagesArea` 的 scroll 事件更新 `userScrolling/autoScrollEnabled`,`scroll-lock-toggle` 按钮切换锁定;思考块单独监听 `scroll` 以保持 pinned 行为。
#### 3.3 输入区(`.compact-input-area`)
- 结构:`stadium-shell` 包含隐藏 ``、左侧 `+` 按钮、`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//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)、`` 语法高亮(`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` 通过 `` 渲染,支持自动消失/手动关闭。
- **Confirm Dialog**:`confirmDialog` + `handleConfirm` 用于危险操作。
- **上下文菜单**:`contextMenu` 仅针对文件树节点(下载文件/文件夹)。
- **Easter Egg Overlay**:`easterEgg.active` 控制 ``,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//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 “上传文件” → `` → `/api/upload`(FormData)→ Toast 过渡 + `refreshFileTree()` → 出错时匹配错误文案(安全审核/禁用类型)。
5. **对话切换**:侧栏点击 → `/api/conversations//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//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` |
| 文件树节点 | `` 组件 | `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。