- 四窗口固定顺序占位布局,空时收起到 0 宽;动画区分「运行中新出现」与「切换/加载」 - 文件记录:edit/write 埋点写入对话 metadata.edited_files,预览走既有 /api/file/content - 详情面板:lastDetail/lastStatus 快照、首次填充静态+瞬间到底、终态四色分类 - 数据通道全部走 REST 轮询(带 conversation_id 对话级隔离),含 demo 与设计文档
10 KiB
10 KiB
对话区快捷窗口栈 · 设计定稿(2026-07-21)
状态:demo 已验收,正式接入
static/src中。 Demo 位置:demo/todo_float_window/(目录名为历史遗留,内含全部 4 个窗口;浏览器直接打开index.html)。 本文档是唯一设计依据;压缩对话后凭本文档 + demo 继续。
0.1 正式接入变更(2026-07-21 用户补充,覆盖 demo 的悬浮定位)
- 命名:该功能正式名称为「快捷窗口」(quick dock / quick window)。
- 布局:占位而非悬浮:快捷窗口不是
position: fixed悬浮,而是在对话区域右侧空白区域占位显示的一列,常驻时会把对话区域向左挤压(与 git/终端 right-panels 同为chat-container的 flex 兄弟节点,位于</main>之后、right-panels 之前)。有内容时才显示该列。 - 设置项:个人空间(PersonalizationDrawer)新增「隐藏快捷窗口」开关,默认关闭(即默认显示)。字段
hide_quick_dock: boolean存 personalization form。 - 详情面板(子智能体/后台指令)保持 fixed 悬浮,从快捷窗口列左侧滑出;文件预览侧边栏在快捷窗口列右侧(git/终端面板左侧)占位/滑出。
- 移动端(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 兄弟节点,宽 294px(270 + 左右 padding 12),flex: none,整列上下排布。对话区被自然向左挤压。 - 窗口顺序(从上到下,固定):待办事项 → 子智能体 → 后台指令 → 文件。
- 窗口上下排布,右对齐,
gap: 12px。 - 整列可滚动:列高 100%,
overflow-y: auto,滚动条隐藏。- 防阴影被 overflow 裁剪:栈
padding: 24px; margin: -24px。 - 栈滚动时关闭所有打开的 ⋯ 菜单(菜单 fixed 定位不随栈滚动)。
- 防阴影被 overflow 裁剪:栈
- 各窗口初始隐藏,有内容时淡入出现(fade + translateY(-6px),0.3s)。
2. 窗口通用规格
- 宽度固定 270px(= 最大宽度 300px × 90%,变量
--window-max-w联动)。 - 列表区高度固定 5 行(行高 36px → 180px),不足留空,超出内部滚动,滚动条隐藏。
- 窗口
flex: none(防止被栈 flex 压缩变矮,已踩坑)。 - 圆角 12px;背景不透明(实体面板禁半透明);中性阴影(无发光);1px 细边框。
- 标题栏 38px:SVG 图标(accent 色)+ 标题(12.5px 次要色)+ 右侧计数(11.5px 三级色)。
- 列表无上下 padding:首行 hover 紧贴标题栏分隔线,末行紧贴窗口底边。
- 行:固定 36px 高,直接铺在窗口上(无嵌套卡片/背景/边框),超长文字省略号。
- 正式接入时配色全部换成三主题语义 token(demo 为经典主题暖色写死)。
3. 各窗口设计
3.1 待办事项
- 行结构:
[状态点] 任务文字;无 hover、不可点击。 - 计数:
done/total。 - 动画:
- 创建:逐行从左向右(位移 14px + 淡入,0.34s,stagger 60ms)。
- 完成:横线从左往右划过文字(260ms,
strike-inscaleX 0→1,origin left)→ 文字延迟 120ms 变灰 + 状态点变色弹跳(dot-pop)。静态完成态(整表渲染时)不播划线,直接呈现。 - 整表替换(收到新 todo):旧行从上到下逐行从右向左移出(0.26s,stagger 45ms,带高度收拢让下方行平滑上移)→ 新行逐行进入。
- 区域外条目:要完成的行未完全显示时,先
scrollIntoView({behavior:'smooth', block:'nearest'})滚出,滚动停稳 90ms 后再播划线(800ms 兜底)。
3.2 子智能体 / 3.3 后台指令(两者同构,仅详情内容不同)
- 行结构:
[●状态点] 名称 [⋯];有 hover,整行可点击;后台指令名称用等宽字体。 - 状态点:运行中 = accent 色呼吸(
status-pulse1.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 去重只出现一次。
- ⋯ 菜单(与按钮左对齐向下展开):
- 下载
- 在文件管理器中打开——复用 git 状态侧边栏已有逻辑,用默认应用打开;docker 模式下无此选项
- 复制路径——工作区内相对路径
- 点击行 → 右侧滑出预览侧边栏(非左侧详情面板):
- 440px 宽、全高(top/bottom 20px),
translateX(100%+24px)↔0,0.3s。 - 打开时悬浮窗栈与详情面板同步左移让位(栈
right: 20+440+12,均带 0.3s transition)。 - 头部:文件图标 + 文件名(等宽加粗)+ 目录(灰小字)+ 关闭按钮。
- 内容:等宽 12px + 行号(44px 灰),行 hover 有底色,滚动条隐藏。
- 再点同一文件 / ✕ / Esc 关闭;点其他文件直接切换。
- 仅支持特定种类 UTF-8 文本文件(正式版按扩展名白名单)。
- 440px 宽、全高(top/bottom 20px),
4. 后端配合点(正式接入)
- 文件记录:每次
write_file/edit_file成功后,把文件相对路径(含时间戳、操作类型)写入对话文件(对话 JSON);同一 path 更新而非追加重复项。 - 前端读取:前端从对话数据中读取文件记录列表渲染文件窗口。
- 文件内容:预览用现有文件内容 API(用户确认已有,无需新做)。
- 待办 / 子智能体 / 后台指令:接各自现有数据流与事件推送。
5. 已踩过的实现坑(接入时避开)
display: flex会覆盖hidden属性的display: none→ 必须补.panel[hidden] { display: none; }。- flex 容器会压缩子元素(窗口变矮)→ 窗口加
flex: none。 animationend会冒泡(feed 行 → 详情面板),用{once:true}监听会被提前消费 → 时序控制改用setTimeout。overflow裁剪窗口阴影 → 滚动容器padding + 负 margin扩大滚动盒。- 菜单 fixed 定位不随栈滚动 → 栈滚动时主动关闭菜单。
- 两个 ⋯ 菜单 + Esc 多层浮层:菜单互斥;Esc 按 菜单 → 详情面板 → 预览栏 顺序逐个关(用
e.preventDefault()+e.defaultPrevented串联)。
6. 正式接入任务清单(2026-07-21 已全部完成)
- 后端:编辑文件路径记录写入对话 JSON(write/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.py:GET /api/conversations/<id>/messages返回edited_files(过滤不存在文件)server/app_legacy.py:terminal_broadcast白名单加edited_files_updatedmodules/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 加载后回填 editedFilesstatic/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 服务重启后的实际运行验证待手动进行。