249 lines
6.0 KiB
Markdown
249 lines
6.0 KiB
Markdown
# AI Gateway Frontend
|
||
|
||
AI 网关管理前端,提供供应商配置和用量统计界面。
|
||
|
||
## 技术栈
|
||
|
||
- **运行时**: Bun
|
||
- **构建工具**: Vite
|
||
- **语言**: TypeScript (strict mode)
|
||
- **框架**: React
|
||
- **UI 组件库**: TDesign
|
||
- **路由**: React Router v7
|
||
- **数据获取**: TanStack Query v5
|
||
- **样式**: SCSS Modules(禁止使用纯 CSS)
|
||
- **测试**: Vitest + React Testing Library + Playwright
|
||
|
||
## API 层
|
||
|
||
### 字段转换机制
|
||
|
||
后端使用 `snake_case`,前端使用 `camelCase`,API 层自动转换:
|
||
|
||
```typescript
|
||
// 发送请求时:camelCase → snake_case
|
||
toApi({ providerId: "openai" }) // → { provider_id: "openai" }
|
||
|
||
// 接收响应时:snake_case → camelCase
|
||
fromApi({ provider_id: "openai" }) // → { providerId: "openai" }
|
||
```
|
||
|
||
### 统一请求函数
|
||
|
||
```typescript
|
||
export async function request<T>(method: string, path: string, body?: unknown): Promise<T>
|
||
```
|
||
|
||
- 自动处理字段转换
|
||
- 自动处理 204 响应(无 body)
|
||
- 抛出 `ApiError` 包含 `status`、`code`、`message`
|
||
|
||
### 错误处理
|
||
|
||
```typescript
|
||
class ApiError extends Error {
|
||
status: number; // HTTP 状态码
|
||
code?: string; // 业务错误码
|
||
message: string; // 错误消息
|
||
}
|
||
```
|
||
|
||
## TanStack Query 模式
|
||
|
||
### Query Keys 定义
|
||
|
||
```typescript
|
||
// src/hooks/useProviders.ts
|
||
export const providerKeys = {
|
||
all: ['providers'] as const,
|
||
};
|
||
|
||
// src/hooks/useModels.ts
|
||
export const modelKeys = {
|
||
all: ['models'] as const,
|
||
byProvider: (providerId: string) => [...modelKeys.all, { providerId }] as const,
|
||
};
|
||
```
|
||
|
||
### Mutation 使用
|
||
|
||
```typescript
|
||
const mutation = useMutation({
|
||
mutationFn: createProvider,
|
||
onSuccess: () => {
|
||
queryClient.invalidateQueries({ queryKey: providerKeys.all });
|
||
},
|
||
});
|
||
```
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
frontend/
|
||
├── src/
|
||
│ ├── api/ # API 层
|
||
│ │ ├── client.ts # 统一 request<T>() + 字段转换
|
||
│ │ ├── providers.ts # Provider CRUD
|
||
│ │ ├── models.ts # Model CRUD
|
||
│ │ └── stats.ts # Stats 查询
|
||
│ ├── components/
|
||
│ │ └── AppLayout/ # 侧边栏导航布局
|
||
│ ├── hooks/ # TanStack Query hooks
|
||
│ │ ├── useProviders.ts
|
||
│ │ ├── useModels.ts
|
||
│ │ └── useStats.ts
|
||
│ ├── pages/
|
||
│ │ ├── Providers/ # 供应商管理(含内嵌模型管理)
|
||
│ │ ├── Stats/ # 用量统计
|
||
│ │ ├── Settings/ # 设置(开发中)
|
||
│ │ └── NotFound.tsx
|
||
│ ├── routes/
|
||
│ │ └── index.tsx # 路由配置
|
||
│ ├── types/
|
||
│ │ └── index.ts # 类型定义
|
||
│ ├── __tests__/ # 测试
|
||
│ │ ├── setup.ts
|
||
│ │ ├── api/
|
||
│ │ ├── hooks/
|
||
│ │ └── components/
|
||
│ ├── App.tsx
|
||
│ ├── main.tsx
|
||
│ └── index.scss
|
||
├── e2e/ # Playwright E2E 测试
|
||
├── vitest.config.ts
|
||
├── playwright.config.ts
|
||
├── tsconfig.json
|
||
├── vite.config.ts
|
||
└── package.json
|
||
```
|
||
|
||
## 运行方式
|
||
|
||
### 安装依赖
|
||
|
||
```bash
|
||
bun install
|
||
```
|
||
|
||
### 开发模式
|
||
|
||
```bash
|
||
bun run dev
|
||
```
|
||
|
||
前端将在端口 5173 启动,API 请求通过 Vite proxy 转发到后端(localhost:9826)。
|
||
|
||
### 构建生产版本
|
||
|
||
```bash
|
||
bun run build
|
||
```
|
||
|
||
### 代码检查
|
||
|
||
```bash
|
||
bun run lint
|
||
```
|
||
|
||
## 测试
|
||
|
||
### 单元测试 + 组件测试
|
||
|
||
```bash
|
||
bun run test # 运行所有测试
|
||
bun run test:watch # 监听模式
|
||
bun run test:coverage # 生成覆盖率报告
|
||
```
|
||
|
||
### E2E 测试
|
||
|
||
```bash
|
||
bun run test:e2e
|
||
```
|
||
|
||
## 功能
|
||
|
||
### 供应商管理
|
||
|
||
- 查看供应商列表(TDesign Table)
|
||
- 添加新供应商(Modal Form)
|
||
- 编辑供应商配置
|
||
- 删除供应商(Popconfirm 确认)
|
||
- API Key 脱敏显示
|
||
- 启用/禁用状态标签
|
||
- **协议字段**:支持 OpenAI 和 Anthropic 协议选择
|
||
|
||
### 模型管理
|
||
|
||
- 展开供应商行查看关联模型
|
||
- 添加/编辑/删除模型
|
||
- 按供应商筛选模型
|
||
- **统一模型 ID**:显示格式为 `provider_id/model_name`,用于跨协议模型识别
|
||
- **UUID 自动生成**:创建模型时后端自动生成 UUID,无需手动输入 ID
|
||
|
||
### 用量统计
|
||
|
||
- 查看统计数据
|
||
- 按供应商筛选
|
||
- 按模型筛选
|
||
- 按日期范围筛选(DatePicker.RangePicker)
|
||
|
||
## 测试策略
|
||
|
||
### 目录结构
|
||
|
||
```
|
||
__tests__/
|
||
├── setup.ts # 测试配置(happy-dom)
|
||
├── api/ # API 层测试
|
||
│ └── client.test.ts
|
||
├── hooks/ # TanStack Query Hook 测试
|
||
│ ├── useProviders.test.ts
|
||
│ └── useModels.test.ts
|
||
└── components/ # 组件测试
|
||
└── AppLayout.test.tsx
|
||
```
|
||
|
||
### E2E 测试
|
||
|
||
- 位于 `e2e/` 目录
|
||
- 使用 Playwright
|
||
- 自动启动后端服务(临时端口 19026)
|
||
- 配置文件:`playwright.config.ts`
|
||
|
||
### Mock 策略
|
||
|
||
- API 层测试使用 MSW(Mock Service Worker)
|
||
- Hook 测试使用 `@testing-library/react-hooks`
|
||
- 组件测试使用 `@testing-library/react`
|
||
|
||
## 环境变量
|
||
|
||
| 变量 | 开发环境 | 生产环境 | 说明 |
|
||
|------|----------|----------|------|
|
||
| `VITE_API_BASE` | (空) | `/api` | API 基础路径,空则走 Vite proxy |
|
||
|
||
**E2E 测试特有**:
|
||
- `NEX_BACKEND_PORT` - E2E 后端端口(默认 19026)
|
||
- `NEX_E2E_TEMP_DIR` - E2E 临时目录
|
||
|
||
## 开发规范
|
||
|
||
- 所有样式使用 SCSS,禁止使用纯 CSS 文件
|
||
- 组件级样式使用 SCSS Modules(*.module.scss)
|
||
- 图标优先使用 TDesign 图标(tdesign-icons-react)
|
||
- TypeScript strict 模式,禁止 any 类型
|
||
- API 层自动处理 snake_case ↔ camelCase 字段转换
|
||
- 使用路径别名 `@/` 引用 src 目录
|
||
|
||
### 环境要求
|
||
|
||
- Bun 1.0 或更高版本
|
||
|
||
### 添加新页面
|
||
|
||
1. 在 `src/pages/` 创建页面目录和组件
|
||
2. 在 `src/hooks/` 创建对应的 TanStack Query hook
|
||
3. 在 `src/routes/index.tsx` 添加路由
|
||
4. 在 `src/components/AppLayout/index.tsx` 的 Menu 中添加 MenuItem
|