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

10 KiB
Raw Blame History

对话区快捷窗口栈 · 设计定稿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 12flex: 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
    • 完成横线从左往右划过文字260msstrike-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×460right: 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 20pxtranslateX(100%+24px)00.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 已全部完成)

  • 后端:编辑文件路径记录写入对话 JSONwrite/edit 钩子)+ 对话数据带出该列表
  • 前端:static/src 快捷窗口占位列容器(非悬浮,挤压对话区)
  • 前端4 个窗口组件 + 详情面板 + 文件预览侧边栏(配色走语义 token 三主题)
  • 前端:接入待办 / 子智能体 / 后台指令 / 文件记录的真实数据与事件推送
  • 前端:文件预览内容接现有文件内容 API扩展名白名单
  • 动画参数按 demo 定稿迁移(位移 14px、stagger 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.pyGET /api/conversations/<id>/messages 返回 edited_files(过滤不存在文件)
  • server/app_legacy.pyterminal_broadcast 白名单加 edited_files_updated
  • modules/personalization_manager.pyhide_quick_dock 字段(默认 False

前端

  • static/src/components/chat/quickdock/QuickDock.vue(占位列容器+菜单+Esc 分层+轮询)、TodoWindow.vueRunnerWindow.vue(子智能体/后台指令通用)、RunnerDetailPanel.vueFileWindow.vueFilePreviewPanel.vuequickdock.css(全部 keyframes 与语义 token 配色)
  • static/src/stores/quickDock.tseditedFiles / detail / previewPath / menu 状态
  • static/src/composables/useLegacySocket.ts:监听 edited_files_updated(按 conversation_id 过滤)
  • static/src/app/methods/history.tsmessages 加载后回填 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 服务重启后的实际运行验证待手动进行。