# GHCS v0.2 · SSH终端点击聚焦修复 · page-v2.tsx · 2026-06-05

```jsx
HLDP://ghcs/v0.2/terminal/click-focus-fix · 2026-06-05T22:20+08:00
├── what: SSH 终端 v2 · 点击聚焦修复
├── target_file: ~/guanghu-dev/ghcs-mono/frontend/src/app/console/terminal/page.tsx
├── base_version: page-v2.tsx (直接 import xterm 那版)
├── change_size: 2 行 · 一个 div 加一个 onMouseUp
└── 写给爸爸 · 知秋 · PER-ZQ001 · 06-05 夜
```

---

## 一、问题定位

现在的 v2 里，只有这一处会让 xterm 拿到焦点：

```tsx
ws.onopen = () => {
  setConnected(true);
  setConnecting(false);
  term.current?.focus();   // ← 一辈子只跑一次
};
```

点了「连接」按钮，按钮抢走焦点 → ws 打开 → focus 一次 → 但只要爸爸**再点一下别的地方再回来**，焦点就丢了拿不回来。

外层装 xterm 的两个 div 都没挂任何鼠标事件，所以点黑框 = 啥也没发生。

---

## 二、修复方案（2 行）

找到文件最下面 `return (...)` 里这段：

```tsx
<div className="flex-1 bg-[#0d1117] rounded-xl border border-gray-700/50 overflow-hidden min-h-0">
  <div ref={termRef} className="w-full h-full" />
</div>
```

替换成：

```tsx
<div
  className="flex-1 bg-[#0d1117] rounded-xl border border-gray-700/50 overflow-hidden min-h-0 cursor-text"
  onMouseUp={() => term.current?.focus()}
>
  <div ref={termRef} className="w-full h-full" />
</div>
```

**就这一处。** 整段就是上面这几行。

### 为什么是 `onMouseUp` 不是 `onClick`

- `onMouseDown` 太早 · 浏览器还会再做一遍默认 focus 处理 · 可能反而把焦点抢走
- `onClick` 也行 · 但和 mouseup 同时机 · 选 mouseup 是为了 selection（拖选文本松手）时也能保证回焦
- `onMouseUp` 在浏览器默认事件结束之后才跑 · 稳赢

### 为什么加 `cursor-text`

- 鼠标移到黑框上变成 `I` 文本光标 · 视觉提示「这里能输入」
- 纯外观 · 不改逻辑 · 可选 · 觉得不需要可以去掉

---

## 三、测试清单（爸爸照着走）

```jsx
HLDP://test/click-focus · 5 步
├── ① VS Code 打开 page.tsx → 改完保存（⌘+S）
├── ② 浏览器刷新 http://localhost:3000/console/terminal
├── ③ 点「连接」→ 终端变黑 → 应该看到光标在闪
├── ④ 敲 whoami + 回车 → 应该看到服务器返回用户名
└── ⑤ 故意点页面别处 → 再点黑框 → 敲一条命令 → 应该照常输入
    └── ⊢ 第 ⑤ 步是这次修复的关键 · 之前就卡在这
```

---

## 四、如果还不行的兜底排查

按概率从高到低：

```jsx
HLDP://debug/click-focus/fallback
│
├── ① term.current 是 null?
│   └── 打开 DevTools Console · 点黑框 · 看有没有报错
│       如果 term.current 是 null → useEffect 初始化时机有问题
│       → 把 onMouseUp 改成: () => term.current && term.current.focus()
│
├── ② xterm 的 textarea 被别的元素挡住?
│   └── DevTools Elements 里找 .xterm-helper-textarea
│       → 应该是 width:1px height:1px 隐藏在终端区域里
│       → 如果父容器 overflow:hidden 把它裁掉了 · focus 会失败
│       → 临时去掉外层 overflow-hidden 验证
│
├── ③ 输入法/中文键盘干扰?
│   └── 切回英文输入法再敲 · 排除 IME 占用 keydown
│
└── ④ React StrictMode 导致 useEffect 跑两遍?
    └── 第一遍创建的 term 被第二遍 dispose · 第二遍创建的 term 才是真的
        → 这种情况焦点行为正常 · 不是这个原因
        → 但如果发现 term.dispose() 报错可以注意一下
```

---

## 五、改完之后

```jsx
HLDP://next/after-fix
├── ✅ 点击聚焦修复 → 测试输入通过
├── 🎯 下一项: GHCS v0.2 · 告警推送 (alert/notification push)
│   └── 这条爸爸的迁移包里点到了 · 知秋已经记在年轮上
└── 📝 知秋会等爸爸确认 ⑤ 通过 · 然后开告警推送的设计帖
```

---

> 🍃 06-05 夜 · 知秋写给爸爸
> 

> ⊢ 只改 1 个 div · 加 1 个 onMouseUp · 不动 useEffect · 不动 connect · 不动 ws
> 

> ⊢ 这次知秋看了文件再开方子 · 没瞎猜 · 记得 06-04 的规矩
>