# 前端开发 本文档说明 alfred 前端的运行时代码结构、组件索引和页面组成。开发规范(组件规范、Ant Design 用法、样式规则、表单交互、TanStack Query、测试约定等)见 [开发规范文档](README.md#开发规范)。 适用场景:修改 `src/web/`、了解现有组件和页面结构、查找 hooks 和工具函数。 ## 运行时外壳 前端提供两个入口外壳,共享通用 Console Shell 组件: - **Admin(管理台)**:`src/web/consoles/admin/AdminConsoleLayout.tsx`,菜单配置在 `src/web/consoles/admin/menu.tsx`,路由 `/`(总览)、`/projects`(项目管理)、`/models`(模型管理)。 - **Workbench(工作台)**:`src/web/consoles/workbench/WorkbenchProjectGate.tsx` → `WorkbenchConsoleLayout.tsx`,菜单配置和路由构造在 `src/web/consoles/workbench/routes.ts`,路由 `/workbench/:projectId` 和 `/workbench/:projectId/chat`。默认菜单为"聊天室"。 通用 Console Shell(`src/web/components/ConsoleShell/ConsoleShell.tsx`)包含 `ConfigProvider`(zhCN locale)、`AntApp`、`Layout`、`Header`、`Sider`、`Content`、主题切换(明亮/黑暗/系统)和侧边栏折叠状态,由 Admin 和 Workbench 复用。Header 显示品牌名、版本号和控制台标题(Admin 显示"管理台",Workbench 显示"工作台 · 项目名")。 Menu 类型定义在 `src/web/menu.tsx` 中的 `MenuItemConfig` 接口(icon、label、path、value)。 Sidebar(`src/web/components/Sidebar/index.tsx`)是纯展示/导航组件,通过 `menuItems` props 接收菜单配置,由调用方决定菜单内容和路径。Admin 传入静态路径 `/`、`/projects`、`/models`;Workbench 通过 route builder(`buildWorkbenchPath`)将相对菜单路径拼成 `/workbench/:projectId` 的子路径。 Workbench 项目上下文通过 `ProjectContext`(`src/web/consoles/workbench/ProjectContext.tsx` 和 `ProjectContextValue.ts`)提供,在 `WorkbenchProjectGate` 中从 URL path param 读取 `projectId`,通过 `useProject(projectId)` 加载项目,仅 active 项目渲染工作台布局,不存在或 archived 项目显示"项目不存在或不可访问"。 ### 页面概览 | 页面 | 路径 | 入口文件 | | -------- | ---------------- | ----------------------------------------------- | | 总览 | `/` | `src/web/pages/dashboard/index.tsx` | | 项目管理 | `/projects` | `src/web/pages/projects/index.tsx` | | 模型管理 | `/models` | `src/web/pages/models/index.tsx` | | 聊天室 | `/workbench/:id` | `src/web/consoles/workbench/pages/ChatPage.tsx` | | 404 | `*` | `src/web/pages/404/index.tsx` | ### 项目管理页面 项目管理页面(`src/web/pages/projects/index.tsx`)使用 `ProjectToolbar`(Tab 切换 active/archived + 搜索 + 新建按钮)、`ProjectTable`(列表展示、内联操作)和 `ProjectFormModal` 拆分职责。支持创建、编辑、归档、恢复和永久删除项目,仅 active 项目可点击跳转工作台。 ### 模型管理页面 模型管理页面(`src/web/pages/models/index.tsx`)通过 antd `Tabs` 在同页组织供应商和模型两个视图。页面使用 `ModelsToolbar`、`ProviderTable`、`ProviderFormModal`、`ModelTable`、`ModelFormModal` 拆分职责;模型表单和模型表格必须使用 `GET /api/providers/options` 获取最小供应商选项。供应商表单支持未保存配置的连通性测试(`POST /api/providers/test`),新建供应商时 type 默认 `openai-compatible`,baseURL 不设默认值。连通性测试返回 `ok: false` 时展示失败反馈;`/models` 不支持属于可忽略提醒,不阻止保存。 ### 聊天页面 Workbench 聊天页面位于 `src/web/consoles/workbench/pages/ChatPage.tsx`,组合 `ChatSidebar` 和 `ChatPanel` 两个子组件。 - **ChatSidebar**(`src/web/consoles/workbench/components/chat/ChatSidebar.tsx`):使用 TanStack Query 管理会话列表,提供创建和删除会话操作。 - **ChatPanel**(`src/web/consoles/workbench/components/chat/ChatPanel.tsx`):使用 Vercel AI SDK `useChat` hook(来自 `@ai-sdk/react`)管理聊天状态,通过 `DefaultChatTransport`(来自 `ai` 包)与后端 SSE 端点通信。采用论坛式单列垂直布局,使用 antd `Card` 组件承载每条消息,通过按 `part.type` 分派渲染(文本/推理/工具调用)。AI 文本使用 `streamdown` 流式 Markdown 渲染。支持编辑上一条用户消息后重新发送、重新生成最后一条 AI 回复、复制消息内容。 - **ChatInputArea**(`src/web/consoles/workbench/components/chat/ChatInputArea.tsx`):使用 antd `Input.TextArea` + `Button` + `Select` 组合,支持模型切换和发送/停止操作。 - **Part renderers**(`src/web/consoles/workbench/components/chat/parts/`):`TextPart.tsx`(Markdown 文本渲染)、`ReasoningPart.tsx`(推理过程)、`ToolPart.tsx`(工具调用展示,支持 input-streaming/input-available/output-available/output-error 四态)。 `use-conversations` hook 位于 `src/web/hooks/use-conversations.ts`,封装会话 CRUD 和消息获取的 fetch 调用。 ## Hooks 索引 | Hook 文件 | 说明 | | -------------------------- | ------------------------------------------------- | | `use-meta.ts` | 获取 `/api/meta`(30s 轮询,5s staleTime) | | `use-projects.ts` | 项目 CRUD + archive/restore API | | `use-providers.ts` | 供应商 CRUD + test connection API | | `use-models.ts` | 模型 CRUD + test connection API | | `use-conversations.ts` | 会话和消息 fetch 函数(不含 Query hooks) | | `use-theme-preference.ts` | 主题偏好(明亮/黑暗/跟随系统)localStorage 持久化 | | `use-sidebar-collapsed.ts` | 侧边栏折叠状态 localStorage 持久化 | ## 工具函数索引 | 文件 | 说明 | | --------------- | --------------------------------------------------------------------------------------------- | | `utils/api.ts` | `handleResponse()`、`handleVoidResponse()` — 通用 fetch 响应处理 | | `utils/time.ts` | `formatCountdown`、`formatDurationUnit`、`formatRelativeTime`、`isOlderThan`、`subtractHours` | ## 更新触发条件 修改前端运行时代码结构、页面组成、组件索引或 hooks/工具清单时,必须更新本文档。