# 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。
