## 1. 架构设计 ```mermaid flowchart TB subgraph Frontend["前端 (React + Vite)"] UI["shadcn/ui 组件层"] Pages["页面层"] Hooks["Hooks 层"] Store["Zustand 状态管理"] SDK["array-sdk 通信层"] end subgraph Backend["后端 (FastAPI + SQLite)"] API["REST API"] WS["WebSocket"] end UI --> Pages Pages --> Hooks Hooks --> Store Hooks --> SDK Store --> SDK SDK --> API SDK --> WS ``` ## 2. 技术说明 - **前端框架**:React 18 + TypeScript + Vite 6 - **UI 组件库**:shadcn/ui(Radix UI + Tailwind CSS) - **状态管理**:Zustand(轻量、无 boilerplate、支持中间件) - **样式方案**:Tailwind CSS 4 + CSS 变量主题系统 - **图标**:Lucide React - **动画**:Framer Motion - **Markdown 渲染**:react-markdown + remark-gfm + rehype-highlight - **HTTP/WebSocket**:array-sdk(从旧项目迁移,纯 JS 无框架依赖) - **路由**:React Router DOM v7(Hash 模式,兼容静态部署) - **国际化**:自定义 i18n hook(中/英双语) - **PWA**:vite-plugin-pwa - **项目初始化**:vite-init react-ts 模板 ## 3. 路由定义 | 路由 | 用途 | |------|------| | `/` | 登录页(未登录时)或主工作台(已登录时) | | `/task/:taskId` | 主工作台,自动选中指定任务 | ## 4. API 定义 本项目为纯前端,所有 API 调用通过 array-sdk 与后端通信。SDK 封装层提供以下接口: ### 4.1 认证 ```typescript interface AuthAPI { login(serverUrl: string, apiKey: string): Promise loginByPassword(serverUrl: string, username: string, password: string): Promise register(serverUrl: string, name: string, username: string, password: string, profile?: RegisterProfile): Promise autoLogin(): Promise logout(): void } ``` ### 4.2 Worker ```typescript interface WorkerAPI { getWorkers(params?: { orgId?: string }): Promise getWorkerProfile(workerId: string): Promise updateProfile(data: Partial): Promise getWorkerWorkload(workerId: string): Promise discoverWorkers(options: DiscoverOptions): Promise } ``` ### 4.3 Task ```typescript interface TaskAPI { getTasks(params?: { orgId?: string; categoryId?: string }): Promise getTask(taskId: string): Promise createTask(title: string, participantIds: string[], priority?: string, extra?: CreateTaskExtra): Promise updateTaskStatus(taskId: string, status: TaskStatus): Promise updateTaskTitle(taskId: string, title: string): Promise addParticipant(taskId: string, workerId: string): Promise removeParticipant(taskId: string, workerId: string): Promise } ``` ### 4.4 Message ```typescript interface MessageAPI { getMessages(taskId: string, scope?: string, includePrivate?: boolean, limit?: number, page?: number): Promise sendMessage(taskId: string, content: string, options?: SendMessageOptions): Promise sendMessageWithAttachments(taskId: string, content: string, fileIds: string[], options?: SendMessageOptions): Promise } ``` ### 4.5 Attachment ```typescript interface AttachmentAPI { uploadAttachment(taskId: string, file: File): Promise listAttachments(taskId: string): Promise<{ attachments: Attachment[]; total: number }> deleteAttachment(taskId: string, attachmentId: string): Promise getAttachmentUrl(taskId: string, attachmentId: string): string } ``` ### 4.6 Organization ```typescript interface OrganizationAPI { listMyOrganizations(): Promise getOrganization(orgId: string): Promise createOrganization(name: string, description?: string): Promise updateOrganization(orgId: string, data: Partial): Promise createInvite(orgId: string, options?: InviteOptions): Promise listInvites(orgId: string): Promise joinOrganization(inviteCode: string): Promise listOrgMembers(orgId: string): Promise removeOrgMember(orgId: string, workerId: string): Promise updateMemberRole(orgId: string, workerId: string, role: 'admin' | 'member'): Promise renameOrgMember(orgId: string, workerId: string, name: string): Promise } ``` ### 4.7 Category ```typescript interface CategoryAPI { createCategory(name: string, orgId?: string): Promise listCategories(orgId?: string): Promise updateCategory(categoryId: string, opts: Partial): Promise deleteCategory(categoryId: string): Promise } ``` ### 4.8 Review ```typescript interface ReviewAPI { createReview(workerId: string, params: CreateReviewParams): Promise getWorkerReviews(workerId: string, options?: PaginationOptions): Promise getReviewSummary(workerId: string): Promise } ``` ### 4.9 Notification ```typescript interface NotificationAPI { getNotifications(isRead?: boolean): Promise markNotificationRead(notificationId: string): Promise markAllNotificationsRead(): Promise } ``` ### 4.10 WebSocket ```typescript interface WebSocketAPI { startWebSocket(callbacks: WSCallbacks): () => void stopWebSocket(): void } interface WSCallbacks { onEvent: (event: WSEvent) => void onConnected: () => void onDisconnected: () => void onError: (err: Error) => void } type WSEventType = 'task.message' | 'participant.joined' | 'task.updated' | 'worker_status_changed' | 'tasks.pending_recovery' ``` ## 5. 数据模型 ```mermaid erDiagram Organization ||--o{ Category : "has" Organization ||--o{ OrgMember : "has" Organization ||--o{ OrgInvite : "has" Worker ||--o{ Task : "creates" Worker ||--o{ Review : "receives" Task ||--o{ Participant : "has" Task ||--o{ Message : "has" Task ||--o{ Attachment : "has" Task }o--|| Category : "belongs_to" Message }o--o| Message : "reply_to" Message }o--o| Worker : "private_to" Worker { string id PK string name string type string status string organization string location string description string[] tags object capabilities number maxConcurrentTasks } Task { string id PK string title string description string status string priority string creator_id FK string org_id FK string category_id FK datetime created_at datetime last_message_at } Message { string id PK string task_id FK string sender_id FK string content string type string reply_to_id FK string private_to_id FK datetime created_at } Attachment { string id PK string task_id FK string filename string content_type number size string url string thumbnail_url number width number height number duration } Review { string id PK string worker_id FK string task_id FK string reviewer_id FK number rating string[] capability_tags string comment string suggestion } ``` ## 6. 项目目录结构 ``` human-adapter-react/ ├── src/ │ ├── components/ # UI 组件 │ │ ├── ui/ # shadcn/ui 基础组件 │ │ ├── layout/ # 布局组件 │ │ │ ├── TopBar.tsx │ │ │ ├── WorkersPanel.tsx │ │ │ ├── TaskList.tsx │ │ │ └── Resizer.tsx │ │ ├── chat/ # 聊天相关组件 │ │ │ ├── ChatDetail.tsx │ │ │ ├── MessageList.tsx │ │ │ ├── MessageBubble.tsx │ │ │ ├── MessageInput.tsx │ │ │ ├── MentionPopup.tsx │ │ │ ├── ReplyPreview.tsx │ │ │ ├── AttachmentRenderer.tsx │ │ │ ├── DMTab.tsx │ │ │ └── ScrollToBottom.tsx │ │ ├── task/ # 任务相关组件 │ │ │ ├── TaskCard.tsx │ │ │ ├── TaskComposer.tsx │ │ │ ├── TaskDrawer.tsx │ │ │ ├── StatusSelector.tsx │ │ │ └── ParticipantManager.tsx │ │ ├── org/ # 组织相关组件 │ │ │ ├── OrgSwitcher.tsx │ │ │ ├── OrgDetailSheet.tsx │ │ │ └── InviteManager.tsx │ │ ├── profile/ # 个人中心组件 │ │ │ ├── ProfileDialog.tsx │ │ │ └── ShortcutSettings.tsx │ │ ├── review/ # 评价组件 │ │ │ ├── ReviewDialog.tsx │ │ │ └── ReviewSummary.tsx │ │ ├── auth/ # 登录组件 │ │ │ └── LoginPage.tsx │ │ └── shared/ # 共享组件 │ │ ├── LedLogo.tsx │ │ ├── LedMatrix.tsx │ │ ├── RobotIcon.tsx │ │ ├── WorkerAvatar.tsx │ │ ├── Toast.tsx │ │ └── PwaInstallBanner.tsx │ ├── hooks/ # 自定义 Hooks │ │ ├── useAuth.ts │ │ ├── useMessages.ts │ │ ├── useWorkers.ts │ │ ├── useTasks.ts │ │ ├── useOrganization.ts │ │ ├── useNotifications.ts │ │ ├── useReviews.ts │ │ ├── useProfile.ts │ │ ├── useWebSocket.ts │ │ ├── useI18n.ts │ │ ├── useTheme.ts │ │ ├── useAutoScroll.ts │ │ └── useDrafts.ts │ ├── stores/ # Zustand Store │ │ ├── authStore.ts │ │ ├── appStore.ts │ │ └── uiStore.ts │ ├── lib/ # 工具库 │ │ ├── sdk.ts # array-sdk 封装 │ │ ├── api.ts # API 薄封装层 │ │ ├── i18n.ts # 国际化字典 │ │ ├── utils.ts # 通用工具函数 │ │ └── constants.ts # 常量定义 │ ├── pages/ # 页面 │ │ ├── LoginPage.tsx │ │ └── WorkbenchPage.tsx │ ├── App.tsx │ ├── main.tsx │ └── index.css # Tailwind 入口 + CSS 变量 ├── public/ ├── sdk-js/ # array-sdk 源码(从旧项目迁移) │ ├── src/ │ │ ├── client.ts │ │ ├── adapter.ts │ │ └── index.ts │ └── package.json ├── .trae/documents/ ├── package.json ├── tsconfig.json ├── vite.config.ts ├── tailwind.config.js ├── components.json # shadcn/ui 配置 └── postcss.config.js ``` ## 7. 关键架构决策 ### 7.1 状态管理:Zustand vs Context 选择 Zustand 的理由: - 无 Provider 包裹,任何组件直接 `useStore()` 即可 - 支持 `subscribeWithSelector` 中间件,精确控制重渲染 - 支持 `persist` 中间件,自动持久化到 localStorage - 比 Redux 少 90% boilerplate,比 Jotai 更适合复杂状态 ```typescript // appStore.ts 示例 import { create } from 'zustand' import { persist } from 'zustand/middleware' interface AppState { workers: Worker[] tasks: Task[] selectedTaskId: string | null wsConnected: boolean setWorkers: (workers: Worker[]) => void setTasks: (tasks: Task[]) => void selectTask: (id: string | null) => void } export const useAppStore = create()( persist( (set) => ({ workers: [], tasks: [], selectedTaskId: null, wsConnected: false, setWorkers: (workers) => set({ workers }), setTasks: (tasks) => set({ tasks }), selectTask: (id) => set({ selectedTaskId: id }), }), { name: 'array-app-store', partialize: (s) => ({ selectedTaskId: s.selectedTaskId }) } ) ) ``` ### 7.2 消息系统:自定义 Hook 不使用 Vercel AI SDK 的 `useChat()`,因为: - 本项目的消息模型更复杂(私密消息、@提及、引用回复、附件) - WebSocket 事件格式是后端自定义的 - 需要精确控制乐观消息的生命周期 自定义 `useMessages` Hook 借鉴 AI SDK 的状态机思想: ```typescript type MessageStatus = 'idle' | 'sending' | 'streaming' | 'error' interface UseMessagesReturn { messages: Message[] pendingMessages: PendingMessage[] isLoading: boolean isAtBottom: boolean sendMessage: (content: string, options?: SendOptions) => Promise retryMessage: (pendingId: string) => Promise cancelMessage: (pendingId: string) => void loadMore: () => Promise hasMore: boolean scrollToBottom: () => void } ``` ### 7.3 主题系统:Tailwind CSS 变量 ```css :root { --background: 0 0% 100%; --foreground: 222.2 84% 4.9%; --primary: 221.2 83.2% 53.3%; --accent: 221.2 83.2% 53.3%; /* ... shadcn 默认变量 */ } .dark { --background: 222.2 84% 4.9%; --foreground: 210 40% 98%; --primary: 217.2 91.2% 59.8%; --accent: 217.2 91.2% 59.8%; } ``` 切换主题只需在 `` 上添加/移除 `dark` 类,所有组件自动响应。 ### 7.4 SDK 迁移策略 array-sdk 是纯 JavaScript,无框架依赖,直接迁移: - `sdk-js/` 目录整体复制到新项目 - `package.json` 中 `"array-sdk": "file:./sdk-js"` 保持不变 - API 封装层 `lib/api.ts` 从旧项目 `api/index.js` 翻译为 TypeScript - 所有方法签名添加 TypeScript 类型 ### 7.5 组件拆分原则 旧项目 TaskDetail.vue 72KB → 拆分为 8+ 个子组件: | 旧代码位置 | 新组件 | 职责 | |------------|--------|------| | 消息流模板 | `MessageList.tsx` | 消息列表渲染 + 时间分割线 | | 单条消息 | `MessageBubble.tsx` | 消息气泡 + 头像 + 引用 + 附件 | | 回复输入栏 | `MessageInput.tsx` | 输入框 + 发送按钮 + 快捷键 | | @提及弹窗 | `MentionPopup.tsx` | 搜索 + 选择参与者 | | 私密消息 | `DMTab.tsx` | 私聊通道列表 + 消息 | | 附件渲染 | `AttachmentRenderer.tsx` | 图片/视频/音频/文件智能渲染 | | 任务抽屉 | `TaskDrawer.tsx` | 参与者 + 详情 + 评价 | | 状态选择器 | `StatusSelector.tsx` | 状态下拉切换 |