agent-Specialization/docs/float_window_design.md
JOJO 171833e4d1 feat(quickdock): 新增对话区右侧快捷窗口(待办/子智能体/后台指令/文件记录)
- 四窗口固定顺序占位布局,空时收起到 0 宽;动画区分「运行中新出现」与「切换/加载」
- 文件记录:edit/write 埋点写入对话 metadata.edited_files,预览走既有 /api/file/content
- 详情面板:lastDetail/lastStatus 快照、首次填充静态+瞬间到底、终态四色分类
- 数据通道全部走 REST 轮询(带 conversation_id 对话级隔离),含 demo 与设计文档
2026-07-22 00:52:36 +08:00

133 lines
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# 对话区快捷窗口栈 · 设计定稿2026-07-21
> 状态demo 已验收,正式接入 `static/src` 中。
> Demo 位置:`demo/todo_float_window/`(目录名为历史遗留,内含全部 4 个窗口;浏览器直接打开 `index.html`)。
> 本文档是唯一设计依据;压缩对话后凭本文档 + demo 继续。
## 0.1 正式接入变更2026-07-21 用户补充,覆盖 demo 的悬浮定位)
1. **命名**:该功能正式名称为「**快捷窗口**」quick dock / quick window
2. **布局:占位而非悬浮**:快捷窗口**不是** `position: fixed` 悬浮,而是在**对话区域右侧空白区域占位显示**的一列,常驻时会**把对话区域向左挤压**(与 git/终端 right-panels 同为 `chat-container` 的 flex 兄弟节点,位于 `</main>` 之后、right-panels 之前)。有内容时才显示该列。
3. **设置项**个人空间PersonalizationDrawer新增「**隐藏快捷窗口**」开关,**默认关闭**(即默认显示)。字段 `hide_quick_dock: boolean` 存 personalization form。
4. 详情面板(子智能体/后台指令)保持 fixed 悬浮从快捷窗口列左侧滑出文件预览侧边栏在快捷窗口列右侧git/终端面板左侧)占位/滑出。
5. 移动端isMobileViewport第一版先隐藏。
## 0. Demo 文件地图
| 文件 | 内容 |
|------|------|
| `index.html` | 页面结构:模拟对话区 + 悬浮栈4 窗口)+ 详情面板 + 预览侧边栏 + 菜单 + toast |
| `style.css` | 变量(配色/尺寸/缓动)+ 窗口基础 + 待办样式与全部 keyframes |
| `app.js` | 待办逻辑(创建/完成/替换/滚动划线) |
| `runner.css` / `runner.js` | 子智能体 + 后台指令窗口、左侧详情面板、⋯ 菜单(强制关闭) |
| `file.css` / `file.js` | 文件记录窗口、右侧预览侧边栏、⋯ 菜单(下载/打开/复制路径、toast |
## 1. 总体布局
- 位置:对话区域右侧**占位列**(非悬浮):`chat-container` 的 flex 兄弟节点,宽 294px270 + 左右 padding 12`flex: none`,整列上下排布。对话区被自然向左挤压。
- 窗口顺序(从上到下,固定):**待办事项 → 子智能体 → 后台指令 → 文件**。
- 窗口上下排布,右对齐,`gap: 12px`。
- **整列可滚动**:列高 100%`overflow-y: auto`,滚动条隐藏。
- 防阴影被 overflow 裁剪:栈 `padding: 24px; margin: -24px`
- 栈滚动时关闭所有打开的 ⋯ 菜单(菜单 fixed 定位不随栈滚动)。
- 各窗口初始隐藏有内容时淡入出现fade + translateY(-6px)0.3s)。
## 2. 窗口通用规格
- **宽度固定 270px**= 最大宽度 300px × 90%,变量 `--window-max-w` 联动)。
- **列表区高度固定 5 行**(行高 36px → 180px不足留空超出内部滚动滚动条隐藏。
- 窗口 `flex: none`(防止被栈 flex 压缩变矮,已踩坑)。
- 圆角 12px背景不透明实体面板禁半透明中性阴影无发光1px 细边框。
- 标题栏 38pxSVG 图标accent 色)+ 标题12.5px 次要色)+ 右侧计数11.5px 三级色)。
- **列表无上下 padding**:首行 hover 紧贴标题栏分隔线,末行紧贴窗口底边。
- 行:固定 36px 高,直接铺在窗口上(无嵌套卡片/背景/边框),超长文字省略号。
- 正式接入时配色全部换成三主题语义 tokendemo 为经典主题暖色写死)。
## 3. 各窗口设计
### 3.1 待办事项
- 行结构:`[状态点] 任务文字`**无 hover、不可点击**。
- 计数:`done/total`。
- 动画:
- **创建**:逐行从左向右(位移 14px + 淡入0.34sstagger 60ms
- **完成**横线从左往右划过文字260ms`strike-in` scaleX 0→1origin left→ 文字延迟 120ms 变灰 + 状态点变色弹跳(`dot-pop`)。静态完成态(整表渲染时)不播划线,直接呈现。
- **整表替换**(收到新 todo旧行从上到下逐行从右向左移出0.26sstagger 45ms**带高度收拢**让下方行平滑上移)→ 新行逐行进入。
- **区域外条目**:要完成的行未完全显示时,先 `scrollIntoView({behavior:'smooth', block:'nearest'})` 滚出,滚动停稳 90ms 后再播划线800ms 兜底)。
### 3.2 子智能体 / 3.3 后台指令(两者同构,仅详情内容不同)
- 行结构:`[●状态点] 名称 [⋯]`**有 hover整行可点击**;后台指令名称用等宽字体。
- 状态点:运行中 = accent 色呼吸(`status-pulse` 1.6s);完成/终止 = 灰,名称同步变灰。
- 计数:`running/total`。
- 新条目:进入动画同待办;**区域外先滚动露出再播进入动画**(先隐身插入,滚动到位后播)。
- **无删除**(条目永久保留)。
- ⋯ 菜单:仅「强制关闭」(警示红色,运行完/已终止置灰);菜单与按钮**右对齐**向下展开两菜单本菜单与文件菜单互斥Esc / 点空白关闭。
- **点击行 → 左侧展开详情面板**480×460`right: calc(20px + 270px + 12px)`,滑入 0.24s
- 子智能体:工具调用 + 文本输出流,**扁平行式无嵌套卡片**;工具行:运行中 spinner旋转→ 完成变 ✓ + 右侧落定结果;文本行次要色。
- 后台指令:等宽终端行,首行 `$ 命令` 加粗。
- 新进度出现动画:淡入 + translateY(5px) 上浮0.25s)。
- **自动滚动**:距底 <80px 时新内容平滑滚到底用户上翻则不打断
- 再点同一行 / / Esc 关闭点其他行切换内容区快速淡入)。
- **实际 API 颗粒度提醒**子智能体进度 API 没有细化的"运行中流式状态"**每个步骤完成后才推送一次进度**。demo 里的流式效果仅为演示正式接入时的显示颗粒度届时再定
### 3.4 文件
- 行结构`[⋯] 文件名`**无状态点** hover整行可点击
- 计数文件总数
- 显示逻辑正式版**文件被编辑/创建过 + 文件仍存在**才显示同一文件按 path 去重只出现一次
- 菜单与按钮**左对齐**向下展开
1. **下载**
2. **在文件管理器中打开**——复用 git 状态侧边栏已有逻辑用默认应用打开**docker 模式下无此选项**
3. **复制路径**——工作区内相对路径
- **点击行 右侧滑出预览侧边栏**非左侧详情面板
- 440px 全高top/bottom 20px`translateX(100%+24px)` `0`0.3s
- 打开时**悬浮窗栈与详情面板同步左移让位** `right: 20+440+12`均带 0.3s transition)。
- 头部文件图标 + 文件名等宽加粗+ 目录灰小字+ 关闭按钮
- 内容等宽 12px + 行号44px hover 有底色滚动条隐藏
- 再点同一文件 / / Esc 关闭点其他文件直接切换
- 仅支持特定种类 UTF-8 文本文件正式版按扩展名白名单)。
## 4. 后端配合点(正式接入)
1. **文件记录**每次 `write_file` / `edit_file` 成功后把文件**相对路径**含时间戳操作类型写入**对话文件对话 JSON**同一 path 更新而非追加重复项
2. **前端读取**前端从对话数据中读取文件记录列表渲染文件窗口
3. **文件内容**预览用**现有文件内容 API**用户确认已有无需新做)。
4. 待办 / 子智能体 / 后台指令接各自现有数据流与事件推送
## 5. 已踩过的实现坑(接入时避开)
1. `display: flex` 会覆盖 `hidden` 属性的 `display: none` 必须补 `.panel[hidden] { display: none; }`
2. flex 容器会压缩子元素窗口变矮)→ 窗口加 `flex: none`
3. `animationend` 会冒泡feed 详情面板 `{once:true}` 监听会被提前消费 时序控制改用 `setTimeout`
4. `overflow` 裁剪窗口阴影 滚动容器 `padding + 负 margin` 扩大滚动盒
5. 菜单 fixed 定位不随栈滚动 栈滚动时主动关闭菜单
6. 两个 菜单 + Esc 多层浮层菜单互斥Esc 菜单 详情面板 预览栏 顺序逐个关 `e.preventDefault()` + `e.defaultPrevented` 串联)。
## 6. 正式接入任务清单2026-07-21 已全部完成)
- [x] 后端编辑文件路径记录写入对话 JSONwrite/edit 钩子+ 对话数据带出该列表
- [x] 前端`static/src` 快捷窗口占位列容器非悬浮挤压对话区
- [x] 前端4 个窗口组件 + 详情面板 + 文件预览侧边栏配色走语义 token 三主题
- [x] 前端接入待办 / 子智能体 / 后台指令 / 文件记录的真实数据与事件推送
- [x] 前端文件预览内容接现有文件内容 API扩展名白名单
- [x] 动画参数按 demo 定稿迁移位移 14pxstagger 60/45ms划线 260ms
### 接入实现位置2026-07-21
**后端**
- `core/main_terminal_parts/tools_execution.py``_record_edited_file` / `_remove_edited_file` / `_rename_edited_file` + `_mutate_edited_files`写入对话 `metadata.edited_files` path 去重广播 `edited_files_updated`
- `server/conversation.py``GET /api/conversations/<id>/messages` 返回 `edited_files`(过滤不存在文件)
- `server/app_legacy.py``terminal_broadcast` 白名单加 `edited_files_updated`
- `modules/personalization_manager.py``hide_quick_dock` 字段(默认 False
**前端**
- `static/src/components/chat/quickdock/``QuickDock.vue`(占位列容器+菜单+Esc 分层+轮询)、`TodoWindow.vue`、`RunnerWindow.vue`(子智能体/后台指令通用)、`RunnerDetailPanel.vue`、`FileWindow.vue`、`FilePreviewPanel.vue`、`quickdock.css`(全部 keyframes 与语义 token 配色)
- `static/src/stores/quickDock.ts`editedFiles / detail / previewPath / menu 状态
- `static/src/composables/useLegacySocket.ts`:监听 `edited_files_updated`(按 conversation_id 过滤)
- `static/src/app/methods/history.ts`messages 加载后回填 editedFiles
- `static/src/App.vue``</main>` 后挂载 `QuickDock` + `FilePreviewPanel`(移动端与 hide_quick_dock 时不渲染)
- `static/src/components/personalization/PersonalizationDrawer.vue`:「隐藏快捷窗口」设置行(默认隐藏工作区之后)
**验证状态**py_compile ✓ / 6 项后端冒烟 ✓ / tsc+stylelint+vite build ✓ / 新文件 eslint 0 问题,存量文件 lint 与基线持平。8091 服务重启后的实际运行验证待手动进行。