Files
hermes-desktop/docs/phases/phase_006.md
T
toor 01d9e301fc
Build / build (push) Canceled after 0s
Playwright / browser (push) Canceled after 0s
initialize Electron desktop app and remove unused files
2026-10-25 01:09:01 +08:00

8.1 KiB
Raw Blame History

Phase 006 — Arco 迁移:聊天页

项 值
目标 聊天页全量换 Arco,功能与旧版完全对等
前置 Phase 005 通过(docs/ui-baseline.md 已定稿)
产出 聊天全流程手工验收清单全绿
参考 docs/03-施工蓝图.md §8.1

0. 为什么聊天页优先

它是全站唯一的 Socket.IO 流式实时页,含审批弹窗、工具轨迹、思考块、Markdown 渲染、虚拟滚动、附件上传。最难的坑在这里踩完,后面 20 个 CRUD 页就是纯体力活。


1. 硬性能规则:消息气泡内禁用 Arco 组件

流式增量渲染时,MessageItem.vue 每次 token 到达都 re-render。Arco 组件被包进消息气泡会引入不必要的 diff 开销。

✅ 允许:a-button(输入区工具条、审批按钮)
✅ 允许:a-modal(审批弹窗,在气泡外层)
❌ 禁止:a-tag / a-avatar / a-progress 等包在气泡内的装饰性组件
❌ 禁止:气泡内任何有内部状态的组件

气泡内用原生 HTML + 项目自己的 SCSS。这条已写进 docs/ui-baseline.md。


2. 改动落点清单

packages/client/src/views/hermes/ChatView.vue
packages/client/src/components/hermes/chat/ChatPanel.vue
packages/client/src/components/hermes/chat/ChatInput.vue
packages/client/src/components/hermes/chat/MessageList.vue
packages/client/src/components/hermes/chat/MessageItem.vue
packages/client/src/components/hermes/chat/VirtualMessageList.vue
packages/client/src/components/hermes/chat/SessionSearchModal.vue
packages/client/src/components/hermes/chat/HistoryMessageList.vue
packages/client/src/components/hermes/chat/FilesPanel.vue
packages/client/src/components/hermes/chat/DrawerPanel.vue
packages/client/src/components/hermes/chat/MarkdownRenderer.vue
packages/client/src/components/hermes/chat/OutlinePanel.vue
packages/client/src/components/hermes/chat/TerminalPanel.vue
packages/client/src/components/hermes/chat/ConversationMonitorPane.vue
packages/client/src/stores/hermes/chat.ts
packages/client/src/stores/hermes/files.ts
packages/client/src/api/hermes/chat.ts

3. 功能任务 1 — 布局与容器

原组件 新组件 备注
NLayout / NLayoutSider a-layout / a-layout-sider 三栏:会话列表 / 聊天区 / 侧面板
NCard a-card 会话项卡片
NScrollbar a-scrollbar 注意:虚拟滚动与 a-scrollbar 冲突,见 §5
NEmpty a-empty 空态
NPopover a-popover 会话项操作菜单
NTooltip a-tooltip
NDrawer a-drawer 侧面板
NCollapse a-collapse 工具轨迹折叠

4. 功能任务 2 — 输入区

原组件 新组件
NInput a-textarea
NButton a-button
NSelect(模型) a-select
NDropdown a-dropdown
NPopconfirm a-popconfirm
NProgress(录音) a-progress
NIcon Arco Icon

ChatInput.vue 里有 useKeyboard / 高度自适应(chat-input-height.test.ts 覆盖),不要重构这块逻辑,只换渲染层。


5. 功能任务 3 — 消息列表(最高风险区)

5.1 虚拟滚动

VirtualMessageList.vue 用 vue-virtual-scroller。

a-scrollbar 与 vue-virtual-scroller 不能同时管滚动容器。二选一:

  • 保留 vue-virtual-scroller 的滚动容器,去掉 a-scrollbar 包裹
  • 或放弃虚拟滚动改 a-table-virtual(不推荐,会破坏消息气泡的自适应高度)

结论:保留 vue-virtual-scroller,去掉 a-scrollbar。在 docs/arco-mapping.md 记下这条例外。

5.2 流式渲染

MessageItem.vue 的 re-render 频率高。确保:

  • 气泡内无 Arco 组件(§1)
  • token 拼接走局部 ref,不触发整列表 diff
  • Markdown 渲染有防抖(保留旧版逻辑)

5.3 审批与澄清弹窗

时序敏感:必须打断流式。这是 a-modal 与流式状态的竞争点。

  • 审批请求到达 → 流式暂停 → 弹窗
  • 用户选择 → 恢复流式
  • 断线重连时若有未处理的审批,要能恢复

MessageItem.vue 里的审批 UI 改成 a-modal 或内联 a-card + a-button(内联更好:不打断视觉连续性)。内联是首选。

5.4 工具轨迹

a-collapse + a-timeline。折叠状态要记住(重渲染不丢)。

5.5 Markdown / 代码 / 图表

MarkdownRenderer.vue 保持不变(不涉及 naive)。相关测试:

markdown-rendering.test.ts
markdown-rendering-mermaid-import-timeout.test.ts
markdown-special-mentions.test.ts
highlight-safety.test.ts
highlight-helper.test.ts

这些不改,跑绿即可。


6. 功能任务 4 — 会话列表

SessionListItem.vue / SessionSearchModal.vue:

原组件 新组件
NCard a-card
NInput(搜索) a-input
NEmpty a-empty
NTag(标签) a-tag
NDropdown a-dropdown
NBadge a-badge
NPopconfirm(删除确认) a-popconfirm

7. 功能任务 5 — 全局 hook 替换

全量 grep 替换,只用 Phase 005 §5 建的适配层:

cd packages/client/src
grep -rln "useMessage\|useDialog\|useNotification" components/hermes/chat/ stores/hermes/chat.ts

改成:

// 旧
const message = useMessage()          // naive hook

// 新
import { useMessage } from '@/composables/useMessage'
const message = useMessage()          // 我们的 composable,签名一致

签名一致,所以正文代码几乎不用改,只改 import 来源。这是 Phase 005 §5 的设计目的。


8. 功能任务 6 — 补测试

新建 tests/client/message-item-arko.test.ts:

  • 消息气泡内不含 Arco 组件标签(防止 §1 规则被破坏)
  • 审批弹窗状态机正确
  • 流式追加消息后 DOM 结构不抖动

9. 验收(手工逐条走,不许跳)

9.1 命令

cd /Users/jack/source/MyProject/js/hermes-ui

grep -cE "from ['\"]naive-ui['\"]" packages/client/src/components/hermes/chat/*.vue \
                         packages/client/src/views/hermes/ChatView.vue \
                         packages/client/src/stores/hermes/chat.ts
# 期望:全部 0

npm run build
npm run test
npm run test:e2e

9.2 手工清单

流式与渲染

  • 发消息 → 流式逐字输出 → 完成态
  • 工具调用轨迹展开 / 收起
  • 思考块(thinking)正常显示 / 隐藏
  • 长消息滚动流畅(虚拟滚动没坏)
  • 滚动到底部自动跟随

交互

  • 审批请求弹出 → 选择 → 流式继续
  • 澄清请求 → 回答 → 继续
  • 中断(stop)按钮生效
  • 重新生成 / 分支切换
  • 会话切换时状态正确重置

内容

  • Markdown 标题 / 列表 / 表格
  • 代码块高亮 + 复制按钮
  • KaTeX 公式
  • Mermaid 图(注意导入超时)
  • @提及高亮

多标签与断线

  • 两个标签页开同一会话(chat-session-multitab.spec.ts)
  • 断网 → 重连 → 流式恢复(chat-run-reconnect.test.ts)
  • 移动端窄屏布局(chat-message-mobile-layout.test.ts)

其他

  • 附件上传 + 引用
  • 文件面板(FilesPanel)正常
  • 大纲面板(OutlinePanel)正常
  • 终端面板(TerminalPanel)正常
  • 会话搜索正常
  • 明暗双主题各过一遍

10. 风险

# 风险 缓解
P6-1 a-scrollbar 与虚拟滚动打架 → 白屏或列表不动 §5.1 已定方案,去掉 a-scrollbar
P6-2 流式性能退化(气泡内 Arco 组件) §1 硬规则 + message-item-arko.test.ts 卡住
P6-3 审批弹窗与流式状态竞争 → 卡死 §5.3 优先内联方案,减少 modal 竞争
P6-4 useMessage 等 hook 改 import 时漏改某个文件 §7 的 grep 逐个确认,编译会兜底
P6-5 顺手重构了 chat store 逻辑 硬规则:只换渲染层,不动逻辑。逻辑改动属 Phase 007+
P6-6 测试大量 fail 干扰判断 先确认 npm run test 的 fail 是否本来就存在(Phase 004 基线),只处理新增

11. 完成标志

进入 Phase 007(其余 20 视图批量迁移)。