Files
T
yinjianm 8c130adcc9 feat(workspace): add cpu core status display and safer quick command actions
Expose `cpuCores` in backend status collection with multi-command fallback
and surface it in the status panel as a localized CPU core badge under the
CPU model.

Adjust terminal group UX by adding a server-level close-all control in the
SSH tab group header.

Reduce accidental quick command execution by switching list interaction to
single-click select + double-click execute, while preserving keyboard Enter
and context-menu execution paths.
2026-04-12 07:22:09 +08:00

5.8 KiB

变更提案: terminal-scroll-viewport-restore-fix

元信息

类型: 缺陷修复
方案类型: implementation
优先级: P1
状态: 实施中
创建: 2026-04-12

1. 需求

背景

当前工作区会为每个 SSH 会话保留一个独立的 xterm 终端实例,并在标签切换、尺寸变化和重新激活时恢复 viewport。现有实现使用“绝对行号”保存滚动位置:当终端持续输出日志、用户又切换到其他服务器后,隐藏期间 buffer.baseY 会继续增长,但保存的绝对行号不会随之更新。重新激活该终端时,组件会把 viewport 恢复到一个已经过时的绝对位置,导致用户向下滚动时很难再追到底部,表现为“鼠标滚轮先向上滚过一次,后面向下滚也到不了最底部”。

目标

  • 修复终端在持续输出日志时切换服务器后出现的滚动恢复异常。
  • 保持现有“在底部时继续贴底、离底部阅读时不强制自动跟随”的总体交互策略不变。
  • 将影响范围控制在前端终端组件,不修改后端会话、WebSocket 协议或工作区布局逻辑。

约束条件

范围约束: 仅修改 packages/frontend 中与 xterm viewport 跟踪和恢复有关的代码与文档
行为约束: 不新增切换服务器后自动跳底的强制行为,不改变用户主动离开底部阅读时的现有语义
兼容性约束: 兼容 keep-alive + v-show 的多终端实例结构,兼容现有 ResizeObserver 和 fit() 调整流程
验证约束: 以 packages/frontend 的 TypeScript 构建通过作为静态验收基线

验收标准

  • 终端处于持续输出日志状态时,切换到其他服务器再切回,若此前贴底则仍能恢复到最底部。
  • 终端离开底部后切换服务器再切回,viewport 恢复应基于“距离底部的偏移”而不是过时的绝对行号,用户继续向下滚动能够重新到达底部。
  • packages/frontend 构建校验通过。

2. 方案

技术方案

Terminal.vue 中的 viewport 快照从“绝对 viewport 行号”改为“距底部的偏移量 + 是否贴底”:

  • 采集快照时记录 distanceFromBottom = baseY - viewportY,而不是仅记录 viewportY
  • 恢复快照时,如果此前处于贴底状态则继续调用 scrollToBottom();如果此前离底部,则按当前最新 baseY - distanceFromBottom 计算目标行并恢复。
  • 保留现有 onScrollResizeObserverfitAndEmitResizeNow() 和激活切换逻辑,仅修正快照语义,避免把过期的绝对行号反复应用到不断增长的缓冲区上。

影响范围

涉及模块:
  - frontend: Terminal.vue 的 viewport 跟踪与恢复逻辑
  - frontend: frontend 模块知识库文档与 CHANGELOG 记录
预计变更文件: 4-5

风险评估

风险 等级 应对
恢复公式错误导致离底部阅读位置跳动 仅替换快照字段语义,复用现有 scrollToBottom/scrollToLine 恢复链路
修改后影响普通贴底场景 保留 shouldStickToBottom 判断,贴底路径不变
构建期间暴露出与本次改动无关的旧错误 先执行前端构建验证,若失败则区分是本次回归还是仓库既有问题

3. 核心场景

场景: 持续日志输出时切换会话后恢复终端

模块: frontend / Terminal.vue 条件: 某个 SSH 终端持续输出日志,用户切换到其他服务器后再切回该终端 行为: 组件在重新激活与 fit() 后恢复 viewport 结果: 若此前贴底则保持贴底;若此前离底部则按距离底部的相对偏移恢复,不会因为隐藏期间日志追加而把终端固定在越来越早的历史位置

场景: 用户手动滚离底部后再向下滚动

模块: frontend / Terminal.vue 条件: 用户曾向上滚动查看历史内容,终端仍在持续输出 行为: 用户向下滚动尝试回到最新输出 结果: viewport 不会被过期快照拖回旧位置,用户可以继续下滚直到重新抵达底部


4. 技术决策

terminal-scroll-viewport-restore-fix#D001: viewport 快照改为记录距底部偏移而非绝对行号

日期: 2026-04-12 状态: 已采纳 背景: 当前问题本质是日志持续输出时 baseY 持续增长,而组件记录的 viewportLine 是静态绝对值。重新激活后按旧绝对值恢复,会让 viewport 相对最新输出越来越靠前。 选项分析:

选项 优点 缺点
A: 保留现有恢复链路,只把快照字段改为“距底部偏移” 改动小,符合现有交互语义,能直接修复会话切换后的滚动异常 仍需依赖现有 fit()/ResizeObserver 链路的稳定性
B: 切换会话后统一强制 scrollToBottom() 实现最简单,用户总能看到最新输出 会改变现有交互语义,破坏用户离底部阅读历史内容的能力
决策: 选择方案 A
理由: 用户已明确要求“只修复当前异常,不额外改动自动跟随策略”。使用相对底部偏移恢复既能消除过时绝对行号带来的问题,又不改变贴底/离底部两种状态的既有语义。
影响: 影响 packages/frontend/src/components/Terminal.vue 的 viewport 快照结构和恢复计算方式,并同步 frontend 模块知识库与变更日志。

5. 成果设计

设计方向

  • 美学基调: N/A,本次为交互缺陷修复,不涉及视觉样式调整
  • 记忆点: N/A
  • 参考: 现有终端交互保持不变

视觉要素

  • 配色: N/A
  • 字体: N/A
  • 布局: N/A
  • 动效: N/A
  • 氛围: N/A

技术约束

  • 可访问性: 不改动现有 DOM 结构与键鼠交互入口
  • 响应式: 保持桌面端与移动端现有 fit()/ResizeObserver 适配流程