# Phase 007 — Arco 迁移:其余 20 视图批量 | 项 | 值 | |---|---| | 目标 | 全仓无 naive-ui;无第二 UI 库 | | 前置 | Phase 006 通过 | | 产出 | `grep -r "naive-ui" packages/client/src` 零命中 | | 参考 | `docs/03-施工蓝图.md` §8.2 | --- ## 0. 批次划分原则 按**耦合度**分批,不按页面重要性。每批独立提交、独立验收,**任何一批都能停下来过夜**。 Phase 006 已经把最难的(流式 / 虚拟滚动 / 审批)趟平了,所以下面每批都是体力活。 --- ## 1. 批次一览 | 批次 | 范围 | 特征 | 风险 | |---|---|---|---| | 7a | Settings / Profiles / Models / Logs | 纯表单 + 表格 | 低 | | 7b | Skills / Plugins / McpManager / Memory | 卡片列表 + 抽屉 | 低 | | 7c | Files / Terminal | 大量 DOM + xterm | **中** | | 7d | Usage / Performance / SkillsUsage / Journey | 图表 / 图谱 + 数据表格 | 中 | | 7e | Kanban / Jobs / Workflow / Devices | 拖拽 + 复杂交互 | 中高 | | 7f | Channels / GroupChat / GlobalAgent | IM 频道 + 群聊 | 中高 | | 7g | History / VersionPreview | 历史会话 | 低 | **7f 排在 7e 之后**:群聊也是流式页,虽然比主聊天简单,但仍有 SSE + 增量渲染,靠近 006 的经验更划算。 --- ## 2. 每批的标准动作(**7a 走一遍,之后照抄**) ### 2.1 开工前 ```bash cd /Users/jack/source/MyProject/js/hermes-ui # 看这批有多少 naive 引用 grep -rc "naive-ui" <本批文件列表> ``` ### 2.2 改法顺序 1. **先建/补 `docs/arco-mapping.md`** —— 本批遇到的 Naive 组件若表里没有,先补进去 2. **Provider 层先换**(`NMessageProvider` → `useMessage()` composable) 3. **容器 → 布局**(`NLayout` → `a-layout`) 4. **表单 → 控件**(`NForm` → `a-form`,逐个 `NFormItem`) 5. **表格 / 列表**(`NDataTable` → `a-table`,差异最大) 6. **交互层**(`NModal` `NDrawer` `NPopconfirm`) 7. **删除所有未用的 naive import**(这一步最容易漏,编译器会兜底) ### 2.3 收尾 ```bash grep -rn "naive-ui" <本批文件> # 期望零命中 npm run build npm run test npm run test:e2e git commit -m "feat(ui): migrate views to Arco Design Vue" ``` ### 2.4 每批完成定义(四条全满足) - [ ] 本批文件 `grep -c naive-ui` 归零 - [ ] `npm run test` 通过 - [ ] e2e 对应用例通过 - [ ] 明暗双主题人工过一遍 --- ## 3. 批次内容 ### 3.1 批次 7a — 纯表单与表格(**先做这批打样**) ``` views/hermes/SettingsView.vue views/hermes/ProfilesView.vue views/hermes/ModelsView.vue views/hermes/LogsView.vue components/hermes/settings/** # 约 20 个组件,含 voice/ 子目录 components/hermes/profiles/** # 6 个 components/hermes/models/** # 约 12 个,含各种 OAuth 登录弹窗 components/hermes/settings/SettingRow.vue components/layout/ModelSelector.vue components/layout/ProfileSelector.vue components/layout/LanguageSwitch.vue components/layout/ThemeSwitch.vue ``` **本批特有难点**: - `NForm` 的校验规则 API 与 `a-form` 不同,需写适配 ``` naive: [{ required: true, message: '...' }] arco: [{ required: true, message: '...' }] # 规则对象基本一致 但 field 绑定方式与 error 展示位置不同 ``` - 各 OAuth 登录弹窗(`AnthropicLoginModal` `CodexLoginModal` `CopilotLoginModal` `GeminiLoginModal` `NousLoginModal` `XaiOAuthLoginModal`)—— 每个都是独立 Modal,改完逐个点 - `SettingRow.vue` 是所有设置项的骨架容器,先改它 **完成后必须过**: ```bash tests/client/default-credential-prompt.test.ts tests/client/copilot-login-modal.test.ts tests/client/platform-card.test.ts tests/client/profile-card-config-edit.test.ts tests/client/provider-card-built-in-action.test.ts tests/client/provider-base-url.test.ts tests/client/display-settings.test.ts tests/client/gateway-auto-start-settings.test.ts tests/client/compression-settings 相关 ``` --- ### 3.2 批次 7b — 卡片列表与抽屉 ``` views/hermes/SkillsView.vue views/hermes/PluginsView.vue views/hermes/McpManagerView.vue views/hermes/MemoryView.vue components/hermes/skills/** # 7 个 components/hermes/mcp/McpServerCard.vue components/hermes/common/RouteLinkItem.vue components/hermes/settings/MemorySettings.vue components/hermes/settings/CompressionSettings.vue ``` **本批特有难点**: - `SkillList` / `SkillDetail` / `SkillImportModal` / `SkillExternalDirsModal` 有复杂表单与文件树 - `PendingWriteApprovals.vue` 有审批交互(与 Phase 006 的审批同源) **完成后必须过**: ```bash tests/client/skills-view.test.ts tests/client/skill-list.test.ts tests/client/skill-detail-edit.test.ts tests/client/plugins-view.test.ts tests/client/pending-write-approvals.test.ts tests/client/route-link-item.test.ts ``` --- ### 3.3 批次 7c — 文件与终端(**别把 Arco 塞进来**) ``` views/hermes/FilesView.vue views/hermes/TerminalView.vue components/hermes/files/** # 9 个 components/hermes/chat/TerminalPanel.vue # 若 7a/7b 未改 composables/useDefaultWorkspace.ts utils/file-path.ts utils/hermes/kanban-assignees.ts ``` **本批特有难点(**本批最特殊**): - **文件树** `FileTree.vue` / `FileList.vue` / `FileBreadcrumb.vue` 是**手写 DOM 结构 + CSS**,不要换成 Arco 的 `a-tree`——会丢掉自定义的文件类型图标、右键菜单、拖拽。 - **xterm.js** 终端是独立 DOM 树,**外面套任何 Arco 布局都可能引入尺寸问题**。终端容器用固定 flex + 原生 CSS。 - `FileContextMenu.vue` / `FilePreview.vue` / `FileEditor.vue` / `FileToolbar.vue` 涉及上传、预览、编辑 - 右键菜单:`a-trigger` 的 `trigger="contextmenu"` **完成后必须过**: ```bash tests/e2e/terminal.spec.ts tests/client/file-tree-profile-scope.test.ts tests/client/file-list-layout.test.ts tests/client/file-context-menu.test.ts tests/client/folder-picker-windows-drives.test.ts tests/client/files-view-profile-config-route.test.ts tests/client/file-path.test.ts ``` --- ### 3.4 批次 7d — 图表与数据密度 ``` views/hermes/UsageView.vue views/hermes/PerformanceView.vue views/hermes/SkillsUsageView.vue views/hermes/JourneyView.vue components/hermes/usage/** # StatCards DailyTrend ModelBreakdown AgentBreakdown api/hermes/journey.ts stores/hermes/usage.ts ``` **本批特有难点**: - **这是 ArkScope 装饰层的第二个合法落点**:Journey 图谱的背景层可以用装饰位面。但**数据线、节点、文字仍必须原生渲染**,装饰只能垫在最底。 - 图表组件(若有 echarts / 自绘 SVG)**不要动**,只换外围容器 - `NDataTable` → `a-table` 在这里是重灾区(数据密度高、列多、有合计行) - 表格横向滚动 + 固定列 **完成后必须过**: ```bash tests/client/usage-components-cache-visuals.test.ts tests/client/usage-view-period.test.ts tests/client/usage-store.test.ts tests/client/skills-usage-view.test.ts ``` --- ### 3.5 批次 7e — 拖拽与复杂交互 ``` views/hermes/KanbanView.vue views/hermes/JobsView.vue views/hermes/WorkflowView.vue views/hermes/DevicesView.vue components/hermes/kanban/** # 4 个 components/hermes/jobs/** # 4 个 components/hermes/workflow/** # 3 个 stores/hermes/kanban.ts stores/hermes/jobs.ts utils/hermes/workflow-skills.ts ``` **本批特有难点**: - **拖拽**(Kanban 列间拖卡片)是**手写 drag 事件**,换成 Arco 布局后要重新验证 drop zone 的坐标计算。**这是本批最大风险。** - `WorkflowAgentNode.vue` 画的是节点图,坐标计算与容器尺寸耦合 - `JobRunHistory` 有时间线 **完成后必须过**: ```bash tests/client/kanban-view.test.ts tests/client/kanban-task-card.test.ts tests/client/kanban-task-drawer.test.ts tests/client/kanban-create-form.test.ts tests/client/kanban-store.test.ts tests/client/kanban-api.test.ts tests/client/jobs.test.ts tests/client/job-form-modal.test.ts tests/client/workflow-skills.test.ts tests/client/workflow-socket.test.ts ``` --- ### 3.6 批次 7f — IM 频道与群聊 ``` views/hermes/ChannelsView.vue views/hermes/GroupChatView.vue views/hermes/GlobalAgentView.vue components/hermes/group-chat/** # GroupChatPanel GroupMessageList GroupMessageItem GroupChatInput CreateRoomForm stores/hermes/group-chat.ts api/hermes/group-chat.ts api/hermes/global-agent.ts ``` **本批特有难点**: - `GroupMessageList` / `GroupMessageItem` 也是**流式增量渲染**,Phase 006 的规则同样适用:气泡内禁用 Arco 组件 - 多 agent 路由的可视化(谁在响应) - 会话设置抽屉 **完成后必须过**: ```bash tests/client/group-chat-store-baseline.test.ts tests/client/group-chat-store-streaming.test.ts tests/client/group-chat-store-workspace.test.ts tests/client/group-chat-view-settings.test.ts tests/client/group-chat-workspace-diff.test.ts tests/client/group-chat-input-mentions.test.ts tests/client/group-chat-mention-options.test.ts tests/client/group-chat-panel-workspace-source.test.ts tests/client/group-message-list-scroll.test.ts tests/client/group-message-item-highlight.test.ts tests/e2e/group-chat-room-deeplink.spec.ts ``` --- ### 3.7 批次 7g — 历史与版本预览(**收尾**) ``` views/hermes/HistoryView.vue views/hermes/VersionPreviewView.vue stores/hermes/app.ts data/changelog.ts # Phase 002 已清空 ``` **本批特有难点**: - `VersionPreviewView` 若 `changelog` 已清空,要么给空态,要么隐藏入口 **完成后必须过**: ```bash tests/e2e/history-session-deeplink.spec.ts tests/client/chat-view-tab-title.test.ts ``` --- ## 4. 收尾(全批次完成后) ### 4.1 删依赖 `package.json` 删: ```jsonc "naive-ui": "...", "@css-render/vue3-ssr": "...", // naive 的 peer,若直接依赖 "vdirs": "..." // 若直接依赖 ``` 先用 `grep -rn "vdirs\|@css-render" packages/client/src` 确认是否真用到。 ### 4.2 改构建配置 `vite.config.ts`: ```ts // manualChunks if (id.includes('naive-ui') || id.includes('vueuc')) return 'ui-vendor' // 改为 if (id.includes('@arco-design')) return 'ui-vendor' // optimizeDeps.include // 删掉 'naive-ui', 'vueuc', '@css-render/vue3-ssr' // 加上 '@arco-design/web-vue' ``` ### 4.3 恢复 `prepare` script Phase 001 摘掉的 `"prepare": "[ -d dist ] || npm run build"` 恢复。 ### 4.4 重写 `style-system.test.ts` 旧版断言的是 Naive 的 theme key。改为断言 Arco token: ```ts // packages/client/src/styles/arco-theme.ts 导出的令牌完整性 // colorPrimary / colorBgLayout / colorBgContainer / borderRadius / fontFamily / fontFamilyMono 存在 // 浅色与深色两套值都定义了 ``` ### 4.5 新增 `no-naive-ui.test.ts`(**防回流,最强保障**) ```ts // 递归扫 packages/client/src // 任何文件出现 "from 'naive-ui'" 或 "from \"naive-ui\"" 即 fail // 同时断言 package.json 的 dependencies 里无 naive-ui ``` ### 4.6 更新 `AGENTS.md` 前端规则 ``` - 使用 Arco Design Vue。新增控件优先从 @arco-design/web-vue/es/icon 取图标。 - 禁止引入第二个 UI 库。 - 消息气泡内部不用 Arco 组件(流式性能)。 - 装饰层一律 pointer-events: none。 ``` ### 4.7 更新 `DEVELOPMENT.md` 的依赖说明 删掉任何 naive 相关表述。 --- ## 5. 验收 ```bash cd /Users/jack/source/MyProject/js/hermes-ui # 全仓零命中 grep -rn "naive-ui\|vueuc\|@css-render" packages/client/src/ grep -n "naive-ui" package.json package-lock.json # 期望:零命中 # 只 Arco 一个 UI 库 grep -nE "\"(naive-ui|element-plus|ant-design-vue|primevue|@arco-design/web-vue)\"" package.json npm ci --ignore-scripts npm run build npm run test:coverage npm run test:e2e ``` ### 手工 - [ ] 全部 24 个视图(20 个 + 登录 + 缺依赖引导)逐个点过 - [ ] 明暗双主题各过一遍 - [ ] Kanban 拖拽正常 - [ ] 文件树正常 - [ ] 终端正常 - [ ] 图表正常 - [ ] 窄屏 / 移动端布局正常 --- ## 6. 风险 | # | 风险 | 缓解 | |---|---|---| | P7-1 | 工作量超预期,7a-7g 拖太久 | 每批独立可停;先做 7a 定模式,再批量 | | P7-2 | 批量改中顺手重构业务逻辑,污染 diff | 硬规则:**只换渲染层**。发现逻辑 bug 单独记 issue,不在本次改 | | P7-3 | Kanban 拖拽坐标在 Arco 布局下算错 | 7e 单独安排时间手测,不与其他批混做 | | P7-4 | 忘记某文件的 naive import | `no-naive-ui.test.ts` 卡住(§4.5) | | P7-5 | `a-table` 替换后大数据量卡顿 | 7d 加虚拟滚动(`a-table-virtual`),先测 1000 行 | | P7-6 | 依赖删了但 lock 没同步,`npm ci` 失败 | 删依赖后 `rm package-lock.json && npm install --package-lock-only` | | P7-7 | 7f 群聊流式性能退化 | 复用 Phase 006 的气泡禁 Arco 规则 | --- ## 7. 完成标志 项目功能完整 + 界面全量 Arco + 无第二 UI 库。进入 Phase 008。