# 前端开发 开发规范见 [开发规范文档](README.md)。 ## 控制台架构 两个控制台入口共享 ConsoleShell(`src/web/components/ConsoleShell/`): - **Admin**(`src/web/consoles/admin/`):路由 `/`(总览)、`/projects`、`/models`。 - **Workbench**(`src/web/consoles/workbench/`):路由 `/workbench/:projectId`、`/workbench/:projectId/chat`。`WorkbenchProjectGate` 从 URL 读 projectId,通过 `ProjectContext` 提供项目上下文,仅 active 项目渲染。 ConsoleShell 包含:`ConfigProvider(zhCN)` + `AntApp` + `Layout`(Header/Sider/Content) + 主题切换(明亮/黑暗/系统)+ 侧边栏折叠。Header 显示品牌名、版本号和控制台标题。 `Sidebar`(`src/web/components/Sidebar/`)纯展示组件,通过 `menuItems` props 接收配置。 ## 页面 | 页面 | 路径 | 入口 | | -------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 总览 | `/` | `pages/dashboard/index.tsx` | | 项目管理 | `/projects` | `pages/projects/index.tsx` — ProjectToolbar(Tab 切换 active/archived + 搜索 + 新建) + ProjectTable + ProjectFormModal。支持创建/编辑/归档/恢复/删除,仅 active 项目可跳转工作台。 | | 模型管理 | `/models` | `pages/models/index.tsx` — antd Tabs 切换供应商/模型视图。模型表单和表格使用 `GET /api/providers/options`。供应商表单支持预保存连通性测试(`POST /api/providers/test`),新建时 type 默认 `openai-compatible`,测试 `ok: false` 展示失败但不阻止保存。 | | 聊天室 | `/workbench/:id` | `consoles/workbench/pages/ChatPage.tsx` | | 404 | `*` | `pages/404/index.tsx` | ### 聊天页面 `ChatPage` = `ChatSidebar` + `ChatPanel`。 - **ChatSidebar**:TanStack Query 管理会话列表,创建/删除操作。 - **ChatPanel**:`useChat`(@ai-sdk/react)+ `DefaultChatTransport`(ai 包)与后端 SSE 通信。按 `part.type` 分派渲染:TextPart(streamdown Markdown)、ReasoningPart、ToolPart(四态)。支持编辑重发、重新生成、复制。 - **ChatInputArea**:`Input.TextArea` + `Button` + `Select`(模型切换)。 ## Hooks | Hook | 说明 | | ----------------------- | ----------------------------------------- | | `use-meta.ts` | `/api/meta`(30s 轮询,5s staleTime) | | `use-projects.ts` | 项目 CRUD + archive/restore | | `use-providers.ts` | 供应商 CRUD + test connection | | `use-models.ts` | 模型 CRUD + test connection | | `use-conversations.ts` | 会话和消息 fetch 函数(不含 Query hooks) | | `use-theme-preference` | 主题偏好 localStorage 持久化 | | `use-sidebar-collapsed` | 侧边栏折叠 localStorage 持久化 | ## 工具函数 | 文件 | 导出 | | --------------- | --------------------------------------------------------------------------------------------- | | `utils/api.ts` | `handleResponse(response, extract)`、`handleVoidResponse(response)` | | `utils/time.ts` | `formatCountdown`、`formatDurationUnit`、`formatRelativeTime`、`isOlderThan`、`subtractHours` | ## 更新触发条件 修改前端技术栈、组件边界、数据流、样式规则、测试环境、前端验证方式、运行时代码结构、页面组成、组件索引或 hooks/工具清单时,必须更新本文档。 ## 日志模块 ### Logger 接口 `src/web/utils/logger.ts` 提供与后端镜像的 Logger 抽象: ```typescript export interface Logger { child(bindings: Record): Logger; debug(message: string, data?: unknown): void; error(message: string, data?: unknown): void; info(message: string, data?: unknown): void; setLevel(level: LogLevel): void; warn(message: string, data?: unknown): void; } ``` ### 实现 | 实现 | 工厂函数 | 用途 | | ----------------------- | --------------------------------------- | ------------------------------------------------------- | | `DefaultLogger` + Sinks | `useLogger()` / `createDefaultLogger()` | 组件内使用,ConsoleSink + AntdMessageSink 双流 | | `ConsoleLogger` | `createConsoleLogger()` | 非组件纯函数(ErrorBoundary、工具函数),仅 ConsoleSink | | `NoopLogger` | `createNoopLogger()` | 测试中不需要日志的场景 | | `MemoryLogger` | `createMemoryLogger()` | 测试断言日志条目 | ### 使用方式 **组件内(推荐):** ```typescript import { useLogger } from "../hooks/use-logger"; function MyComponent() { const logger = useLogger(); logger.info("数据加载完成", { count: 42 }); logger.warn("即将超时"); logger.error("操作失败", { error: new Error("...") }); } ``` **非组件纯函数:** ```typescript import { createConsoleLogger } from "../utils/logger"; const logger = createConsoleLogger(); logger.debug("调试信息"); ``` **作用域绑定:** ```typescript const pageLogger = logger.child({ page: "projects" }); pageLogger.info("页面加载"); // [Alfred:INFO] 页面加载 [page=projects] ``` ### notification 红线 - `AntdMessageSink` 仅对 **warn**(`message.warning`)和 **error**(`message.error`)触发用户可见通知。 - `debug` 和 `info` 级别绝不对用户弹出 notification,仅在开发者控制台输出。 - 错误详情通过 `data` 参数传入(如 `logger.error("提交失败", { error })`),`data` 不经序列化透传,保留 Error 堆栈展开能力。 ### 生产环境行为 生产环境(`import.meta.env["PROD"]`)自动将 ConsoleSink 最小级别设为 `warn`,屏蔽 debug/info 输出。`useLogger()` 和 `createConsoleLogger()` 自动处理此逻辑,调用方无需关心环境判断。 ### ErrorBoundary 特殊说明 `ErrorBoundary` 是 class 组件,无法使用 `useLogger()` hook。它以 `createConsoleLogger()` 直接创建独立的 ConsoleLogger 实例,仅输出到控制台不触发用户通知。 ### 测试 - 单元测试使用 `createMemoryLogger()` 断言日志记录,使用 `createNoopLogger()` 静默无关日志。 - `createDefaultLogger(sinks, isProduction)` 接受 `isProduction` 参数,测试中可显式控制级别过滤行为,不依赖 `import.meta.env`。