# Browser Hand UI 组件设计文档 > **日期**: 2026-03-17 > **状态**: Draft > **作者**: Claude Code ## 一、概述 Browser Hand 是 ZCLAW 的浏览器自动化能力,基于 Fantoccini (Rust WebDriver) 实现。本设计文档描述其前端 UI 组件架构和集成方案。 ### 设计目标 1. **双层触发机制**: 前端任务模板 + Agent 脚本驱动 2. **实时可视化**: 执行状态 + 截图预览 3. **完整工具集**: 支持所有浏览器自动化功能 4. **标准集成**: 作为 Hand 集成到现有 HandsPanel ### 范围 - 前端 UI 组件 - 状态管理 Store - 任务模板系统 - 与现有 HandsPanel 集成 --- ## 二、架构设计 ### 2.1 组件结构 ``` desktop/src/ ├── components/ │ ├── HandsPanel.tsx # 现有,添加 Browser Hand 特殊处理 │ └── BrowserHand/ │ ├── index.ts # 模块导出 │ ├── BrowserHandCard.tsx # Browser Hand 专用卡片 │ ├── TaskTemplateModal.tsx # 任务模板选择模态框 │ ├── TaskRunner.tsx # 任务执行状态展示 │ ├── ScreenshotPreview.tsx # 截图预览组件 │ └── templates/ │ ├── index.ts # 模板注册 │ ├── types.ts # 模板类型定义 │ ├── basic.ts # 基础操作模板 │ ├── scraping.ts # 数据采集模板 │ └── automation.ts # 自动化流程模板 ├── lib/ │ ├── browser-client.ts # 已完成 - Tauri API 封装 │ └── browser-templates.ts # 模板执行引擎 └── store/ └── browserHandStore.ts # Browser Hand 状态管理 ``` ### 2.2 数据流 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 前端触发流程 │ ├─────────────────────────────────────────────────────────────────┤ │ HandsPanel │ │ ↓ 检测 Browser Hand │ │ BrowserHandCard │ │ ↓ 点击"执行任务" │ │ TaskTemplateModal │ │ ↓ 选择模板 + 填参数 │ │ browserHandStore.executeTemplate() │ │ ↓ 调用 │ │ Tauri Commands (browser_*) │ │ ↓ WebDriver Protocol │ │ Fantoccini → ChromeDriver │ └─────────────────────────────────────────────────────────────────┘ ┌─────────────────────────────────────────────────────────────────┐ │ Agent 触发流程 │ ├─────────────────────────────────────────────────────────────────┤ │ 用户对话 │ │ ↓ 理解意图 │ │ LLM 生成脚本 │ │ ↓ Agent 调用 │ │ browserHandStore.executeScript() │ │ ↓ 调用 │ │ Tauri Commands (browser_execute_script) │ │ ↓ WebDriver Protocol │ │ Fantoccini → ChromeDriver │ └─────────────────────────────────────────────────────────────────┘ ``` ### 2.3 与现有系统集成 ```typescript // HandsPanel.tsx 修改 import { BrowserHandCard } from './BrowserHand'; function HandsPanel() { // 检测是否为 Browser Hand const isBrowserHand = (hand: Hand) => hand.id === 'browser' || hand.name === 'Browser'; return (
{hands.map((hand) => isBrowserHand(hand) ? ( ) : ( ) )}
); } ``` --- ## 三、状态管理 ### 3.1 Store 结构 ```typescript // store/browserHandStore.ts interface BrowserSession { id: string; name: string; currentUrl: string | null; title: string | null; status: 'connecting' | 'connected' | 'active' | 'idle' | 'error'; createdAt: string; lastActivity: string; } interface BrowserLog { id: string; timestamp: string; level: 'info' | 'warn' | 'error' | 'action'; message: string; details?: Record; } interface ExecutionState { isRunning: boolean; currentAction: string | null; currentUrl: string | null; lastScreenshot: string | null; progress: number; // 0-100 startTime: string | null; } interface RecentTask { id: string; templateId: string; templateName: string; params: Record; status: 'success' | 'failed' | 'cancelled'; executedAt: string; duration: number; result?: unknown; } interface BrowserHandState { // 会话管理 sessions: BrowserSession[]; activeSessionId: string | null; // 执行状态 execution: ExecutionState; // 日志 logs: BrowserLog[]; // 模板 templates: TaskTemplate[]; recentTasks: RecentTask[]; // UI 状态 isTemplateModalOpen: boolean; isLoading: boolean; error: string | null; } interface BrowserHandActions { // 会话管理 createSession: (options?: SessionOptions) => Promise; closeSession: (sessionId: string) => Promise; listSessions: () => Promise; // 模板执行 executeTemplate: (templateId: string, params: Record) => Promise; executeScript: (script: string, args?: unknown[]) => Promise; // 状态更新 updateExecutionState: (state: Partial) => void; addLog: (log: Omit) => void; // 截图 takeScreenshot: () => Promise; // UI 控制 openTemplateModal: () => void; closeTemplateModal: () => void; clearError: () => void; } ``` ### 3.2 Store 实现要点 ```typescript // 使用 Zustand 创建 store export const useBrowserHandStore = create((set, get) => ({ // 初始状态 sessions: [], activeSessionId: null, execution: { isRunning: false, currentAction: null, currentUrl: null, lastScreenshot: null, progress: 0, startTime: null, }, logs: [], templates: BUILTIN_TEMPLATES, recentTasks: [], isTemplateModalOpen: false, isLoading: false, error: null, // Actions 实现见详细设计 })); ``` --- ## 四、任务模板系统 ### 4.1 模板类型定义 ```typescript // components/BrowserHand/templates/types.ts interface TaskTemplateParam { key: string; label: string; type: 'text' | 'url' | 'number' | 'select' | 'textarea' | 'json'; required: boolean; default?: unknown; placeholder?: string; options?: { value: string; label: string }[]; // for select type description?: string; } interface TaskTemplate { id: string; name: string; description: string; category: 'basic' | 'scraping' | 'automation'; icon: string; params: TaskTemplateParam[]; execute: (params: Record, context: ExecutionContext) => Promise; } interface ExecutionContext { browser: Browser; // browser-client.ts 中的 Browser 类 onProgress: (action: string, progress: number) => void; onLog: (level: BrowserLog['level'], message: string, details?: Record) => void; } ``` ### 4.2 内置模板列表 #### 基础操作类 (Basic) | ID | 名称 | 参数 | 说明 | |----|------|------|------| | `basic_navigate_screenshot` | 打开网页并截图 | `url` | 访问指定 URL 并截图 | | `basic_fill_form` | 填写表单 | `url`, `fields[]` | 填写并可选提交表单 | | `basic_click_navigate` | 点击导航 | `url`, `selector` | 点击指定元素 | #### 数据采集类 (Scraping) | ID | 名称 | 参数 | 说明 | |----|------|------|------| | `scrape_text` | 抓取页面文本 | `url`, `selectors[]` | 提取多个选择器的文本 | | `scrape_list` | 提取列表数据 | `url`, `itemSelector`, `fieldMappings` | 批量提取结构化数据 | | `scrape_images` | 下载图片 | `url`, `imageSelector`, `savePath` | 批量下载图片 | #### 自动化流程类 (Automation) | ID | 名称 | 参数 | 说明 | |----|------|------|------| | `auto_login_action` | 登录并操作 | `loginUrl`, `credentials`, `actions[]` | 登录后执行操作序列 | | `auto_multi_page` | 多页面导航 | `urls[]`, `actions[]` | 遍历多个页面执行操作 | | `auto_monitor` | 定时监控 | `url`, `checkCondition`, `interval` | 周期性检查页面状态 | ### 4.3 模板执行引擎 ```typescript // lib/browser-templates.ts export async function executeTemplate( template: TaskTemplate, params: Record, browser: Browser, onProgress: (action: string, progress: number) => void, onLog: (level: BrowserLog['level'], message: string) => void ): Promise { const context: ExecutionContext = { browser, onProgress, onLog: (level, message, details) => { onLog(level, message); console.log(`[BrowserHand] ${level}: ${message}`, details); }, }; // 验证参数 validateParams(template.params, params); // 执行模板 onProgress('启动浏览器', 0); try { const result = await template.execute(params, context); onProgress('完成', 100); return result; } catch (error) { onLog('error', `执行失败: ${error}`); throw error; } } ``` --- ## 五、UI 组件设计 ### 5.1 BrowserHandCard Browser Hand 的专用卡片组件,显示实时状态和截图预览。 ``` ┌────────────────────────────────────────────────────────────┐ │ 🌐 Browser Hand [●] 就绪/运行中 │ ├────────────────────────────────────────────────────────────┤ │ 浏览器自动化能力 - 支持网页操作、数据采集、自动化流程 │ ├────────────────────────────────────────────────────────────┤ │ ┌────────────────────────────────────────────────────────┐ │ │ │ 截 图 预 览 │ │ │ │ (最近一次截图) │ │ │ └────────────────────────────────────────────────────────┘ │ │ 当前: https://example.com/page │ │ 操作: 正在填写表单... ████████░░ 80% │ ├────────────────────────────────────────────────────────────┤ │ [📋 执行任务] [📸 截图] [🔄 刷新] [⚙️ 设置] │ └────────────────────────────────────────────────────────────┘ ``` **Props**: ```typescript interface BrowserHandCardProps { hand: Hand; onOpenSettings?: () => void; } ``` **状态显示**: - `idle`: 显示"就绪",截图区域显示占位符 - `running`: 显示进度条、当前操作、最新截图 - `error`: 显示错误信息、重试按钮 ### 5.2 TaskTemplateModal 任务模板选择和参数填写模态框。 ``` ┌────────────────────────────────────────────────────────────┐ │ 选择任务模板 ✕ │ ├────────────────────────────────────────────────────────────┤ │ [基础操作] [数据采集] [自动化流程] │ ├────────────────────────────────────────────────────────────┤ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 📸 打开截图 │ │ 📝 填写表单 │ │ 🖱️ 点击导航 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ 📄 抓取文本 │ │ 📊 提取列表 │ │ │ └──────────────┘ └──────────────┘ │ ├────────────────────────────────────────────────────────────┤ │ 已选: 📸 打开网页并截图 │ │ │ │ 网页地址 * │ │ ┌────────────────────────────────────────────────────────┐│ │ │ https://example.com ││ │ └────────────────────────────────────────────────────────┘│ ├────────────────────────────────────────────────────────────┤ │ [取消] [▶ 执行任务] │ └────────────────────────────────────────────────────────────┘ ``` **Props**: ```typescript interface TaskTemplateModalProps { isOpen: boolean; onClose: () => void; onSelect: (template: TaskTemplate, params: Record) => void; } ``` ### 5.3 TaskRunner 任务执行中的状态展示组件(可嵌入 BrowserHandCard 或独立显示)。 ``` ┌────────────────────────────────────────────────────────────┐ │ 执行中: 打开网页并截图 │ ├────────────────────────────────────────────────────────────┤ │ ┌────────────────────────────────────────────────────────┐ │ │ │ 实 时 截 图 │ │ │ └────────────────────────────────────────────────────────┘ │ │ │ │ 当前 URL: https://example.com/page │ │ 操作: 等待页面加载... │ │ │ │ ████████████████████░░░░░░░░░░ 65% │ │ │ │ ┌─ 操作日志 ─────────────────────────────────────────────┐│ │ │ 10:23:01 [info] 创建浏览器会话 ││ │ │ 10:23:02 [info] 导航到 https://example.com ││ │ │ 10:23:05 [action] 等待页面加载 ││ │ └────────────────────────────────────────────────────────┘│ ├────────────────────────────────────────────────────────────┤ │ [⏹ 停止] [📋 查看结果] │ └────────────────────────────────────────────────────────────┘ ``` ### 5.4 ScreenshotPreview 截图预览组件,支持缩放和全屏查看。 ```typescript interface ScreenshotPreviewProps { base64: string | null; isLoading?: boolean; onRefresh?: () => void; onClick?: () => void; // 点击放大 } ``` --- ## 六、错误处理 ### 6.1 错误类型 ```typescript enum BrowserHandErrorType { WEBDRIVER_NOT_AVAILABLE = 'webdriver_not_available', SESSION_CREATION_FAILED = 'session_creation_failed', NAVIGATION_FAILED = 'navigation_failed', ELEMENT_NOT_FOUND = 'element_not_found', TIMEOUT = 'timeout', SCRIPT_ERROR = 'script_error', PERMISSION_DENIED = 'permission_denied', } ``` ### 6.2 错误处理策略 | 错误类型 | 处理方式 | |---------|---------| | WEBDRIVER_NOT_AVAILABLE | 显示安装指引,提供下载链接 | | SESSION_CREATION_FAILED | 重试按钮,显示详细错误 | | NAVIGATION_FAILED | 显示 URL,提供重试 | | ELEMENT_NOT_FOUND | 显示选择器,建议检查页面 | | TIMEOUT | 提供增加超时时间选项 | | SCRIPT_ERROR | 显示脚本错误位置和消息 | --- ## 七、测试策略 ### 7.1 单元测试 - `browserHandStore` 状态管理测试 - 模板参数验证测试 - 错误处理测试 ### 7.2 集成测试 - 模板执行流程测试(mock Tauri commands) - UI 组件渲染测试 - 与 HandsPanel 集成测试 ### 7.3 E2E 测试 - 完整任务执行流程 - 多模板顺序执行 - 错误恢复流程 --- ## 八、实现优先级 ### Phase 1: 核心框架 1. `browserHandStore` 状态管理 2. `BrowserHandCard` 基础组件 3. 集成到 `HandsPanel` ### Phase 2: 模板系统 4. 模板类型定义和注册 5. `TaskTemplateModal` 组件 6. 基础操作类模板实现 ### Phase 3: 完整功能 7. 数据采集类模板 8. 自动化流程类模板 9. `TaskRunner` 实时状态展示 10. 截图预览功能 --- ## 九、依赖 - `browser-client.ts` (已完成) - Tauri browser commands (已完成) - Fantoccini WebDriver (已完成) - Zustand (已有) - Lucide React icons (已有) - Tailwind CSS (已有) --- ## 十、风险与缓解 | 风险 | 影响 | 缓解措施 | |------|------|---------| | WebDriver 未安装 | 无法使用 | 提供安装检测和指引 | | 大量截图消耗内存 | 性能下降 | 限制截图历史数量,压缩图片 | | 脚本执行安全 | 潜在危险操作 | Agent 层审批机制 | | 复杂模板难以调试 | 用户体验差 | 详细日志,步骤高亮 | --- ## 十一、未来扩展 - [ ] 录制回放功能 - [ ] 模板自定义创建 - [ ] 多浏览器并行 - [ ] Chrome DevTools Protocol 直接集成 - [ ] WebMCP 支持 (Chrome 146+)