# 前端配置界面 ## Purpose TBD - 提供供应商、模型配置和用量统计的前端管理界面 ## Requirements ### Requirement: 提供供应商管理页面 前端 SHALL 使用 Ant Design 组件提供供应商管理页面。 #### Scenario: 显示供应商列表 - **WHEN** 加载供应商管理页面 - **THEN** 前端 SHALL 使用 Ant Design Table 显示所有已配置供应商 - **THEN** 每个供应商 SHALL 显示 name、base_url 和 enabled 状态(使用 Tag 组件) - **THEN** API Key SHALL 被脱敏显示(掩码处理) - **THEN** 表格 SHALL 支持展开行以显示关联模型 - **THEN** 表格 SHALL 设置 `scroll={{ x: 'max-content' }}` 防止窄屏溢出 #### Scenario: 表格列宽约束 - **WHEN** 渲染供应商表格 - **THEN** 名称列 SHALL 固定宽度 180px 并启用 ellipsis(超长文本显示省略号,hover 显示 Tooltip) - **THEN** Base URL 列 SHALL 不设固定宽度(浮动填充剩余空间)并启用 ellipsis + Tooltip - **THEN** API Key 列 SHALL 固定宽度 120px 并启用 ellipsis - **THEN** 状态列 SHALL 固定宽度 80px - **THEN** 操作列 SHALL 固定宽度 160px #### Scenario: 表格空状态 - **WHEN** 供应商列表为空 - **THEN** 表格 SHALL 显示自定义空状态文案 "暂无供应商,点击上方按钮添加" #### Scenario: 添加新供应商 - **WHEN** 用户点击"添加供应商"按钮 - **THEN** 前端 SHALL 使用 Ant Design Modal + Form 显示输入表单 - **THEN** 表单 SHALL 包含 id、name、api_key、base_url 字段,带校验规则 - **WHEN** 用户提交包含有效数据的表单 - **THEN** 前端 SHALL 通过 useMutation 调用创建 API - **THEN** 成功后 SHALL 关闭 Modal 并刷新供应商列表 - **THEN** 失败 SHALL 使用 message.error() 提示 #### Scenario: 编辑现有供应商 - **WHEN** 用户点击供应商的"编辑"按钮 - **THEN** 前端 SHALL 使用 Ant Design Modal + Form 显示预填充数据的表单 - **WHEN** 用户提交包含更新数据的表单 - **THEN** 前端 SHALL 通过 useMutation 调用更新 API - **THEN** 成功后 SHALL 关闭 Modal 并刷新供应商列表 #### Scenario: 删除供应商 - **WHEN** 用户点击供应商的"删除"按钮 - **THEN** 前端 SHALL 使用 Ant Design Popconfirm 弹出确认 - **WHEN** 用户确认删除 - **THEN** 前端 SHALL 通过 useMutation 调用删除 API - **THEN** 成功后 SHALL 刷新供应商列表 ### Requirement: 提供模型管理界面 前端 SHALL 在供应商页面展开行中提供模型管理。 #### Scenario: 显示供应商的模型 - **WHEN** 展开供应商行 - **THEN** 前端 SHALL 显示该供应商的模型列表 - **THEN** 每个模型 SHALL 显示 model_name 和 enabled 状态 - **THEN** 模型名称列 SHALL 启用 ellipsis(超长文本显示省略号,hover 显示 Tooltip) #### Scenario: 模型表格空状态 - **WHEN** 模型列表为空 - **THEN** 表格 SHALL 显示自定义空状态文案 "暂无模型,点击上方按钮添加" #### Scenario: 为供应商添加模型 - **WHEN** 用户在展开行中点击"添加模型" - **THEN** 前端 SHALL 显示 Ant Design Modal + Form - **THEN** provider_id SHALL 自动关联当前供应商 - **WHEN** 用户提交表单 - **THEN** 前端 SHALL 通过 useMutation 调用创建 API - **THEN** 成功后 SHALL 刷新模型列表 #### Scenario: 编辑模型 - **WHEN** 用户点击模型的"编辑" - **THEN** 前端 SHALL 显示编辑表单 - **WHEN** 用户提交表单 - **THEN** 前端 SHALL 通过 useMutation 调用更新 API - **THEN** 成功后 SHALL 刷新模型列表 #### Scenario: 删除模型 - **WHEN** 用户点击模型的"删除" - **THEN** 前端 SHALL 使用 Popconfirm 弹出确认 - **WHEN** 用户确认删除 - **THEN** 前端 SHALL 通过 useMutation 调用删除 API - **THEN** 成功后 SHALL 刷新模型列表 ### Requirement: 提供统计查看页面 前端 SHALL 使用 Ant Design 组件提供统计仪表盘页面。 #### Scenario: 显示统计概览 - **WHEN** 加载统计页面 - **THEN** 前端 SHALL 在顶部显示统计摘要卡片(总请求量、活跃模型数、活跃供应商数、今日请求量) - **THEN** 统计摘要数据 SHALL 从 stats API 返回数据中前端聚合 - **THEN** 前端 SHALL 显示请求趋势折线图 - **THEN** 前端 SHALL 使用 Ant Design Table 显示统计数据 - **THEN** 统计数据 SHALL 按供应商和模型显示请求计数 - **THEN** 统计表格 SHALL 设置 `scroll={{ x: 'max-content' }}` 防止窄屏溢出 #### Scenario: 统计表格列宽约束 - **WHEN** 渲染统计表格 - **THEN** 供应商列 SHALL 固定宽度 180px 并启用 ellipsis + Tooltip - **THEN** 模型列 SHALL 固定宽度 250px 并启用 ellipsis + Tooltip - **THEN** 日期列 SHALL 固定宽度 120px - **THEN** 请求数列 SHALL 固定宽度 100px 并右对齐 #### Scenario: 统计表格空状态 - **WHEN** 统计数据为空 - **THEN** 表格 SHALL 显示自定义空状态文案 "暂无统计数据" #### Scenario: 按供应商过滤统计 - **WHEN** 用户从 Ant Design Select 选择供应商 - **THEN** 前端 SHALL 自动查询并过滤统计 - **THEN** 统计摘要卡片和趋势图表 SHALL 同步更新 #### Scenario: 按日期范围过滤统计 - **WHEN** 用户使用 Ant Design DatePicker.RangePicker 选择日期范围 - **THEN** 前端 SHALL 自动查询并过滤统计 - **THEN** 统计摘要卡片和趋势图表 SHALL 同步更新 ### Requirement: 优雅处理 API 错误 前端 SHALL 处理 API 错误并显示用户友好的消息。 #### Scenario: API 请求失败 - **WHEN** API 请求失败(网络错误、4xx、5xx) - **THEN** 前端 SHALL 使用 Ant Design 的 message.error() 显示全局错误提示 - **THEN** 错误消息 SHALL 具有描述性 #### Scenario: 验证错误 - **WHEN** 用户提交包含无效数据的表单 - **THEN** 前端 SHALL 在相关字段旁显示验证错误 - **THEN** 前端 SHALL 阻止表单提交 ### Requirement: 提供响应式布局 前端 SHALL 使用 Ant Design Layout 提供侧边栏导航布局。 #### Scenario: 桌面布局 - **WHEN** 在桌面屏幕上查看前端(宽度 >= 992px) - **THEN** 布局 SHALL 使用 Ant Design `Layout.Sider` + `Menu`(inline 模式) - **THEN** 侧边栏 SHALL 显示导航菜单,包含图标和文字标签 - **THEN** 侧边栏 SHALL 可通过折叠按钮折叠为仅图标模式 #### Scenario: 响应式折叠 - **WHEN** 屏幕宽度小于 992px - **THEN** 侧边栏 SHALL 自动折叠为图标模式 - **THEN** 折叠后侧边栏宽度 SHALL 为 80px - **THEN** 菜单项 SHALL 仅显示图标 #### Scenario: 页面内容区域 - **WHEN** 显示页面内容 - **THEN** 内容区域 SHALL 在 `Layout.Content` 中渲染 - **THEN** 页面之间 SHALL 通过 React Router Outlet 渲染 #### Scenario: Header 区域 - **WHEN** 渲染页面 Header - **THEN** Header SHALL 仅显示当前页面标题 - **THEN** Header SHALL 不包含导航菜单 ### Requirement: 使用无组件库的最小 UI 前端 SHALL 使用 Ant Design 6 作为 UI 组件库。 #### Scenario: Ant Design 组件使用 - **WHEN** 实现前端 - **THEN** 它 SHALL 使用 Ant Design 6 组件(Table、Form、Modal、Menu、Tag、Popconfirm、DatePicker、Button、Select 等) - **THEN** 它 SHALL 使用 @ant-design/icons 提供图标 - **THEN** 图标 SHALL 优先使用图标库中已有的图标 #### Scenario: Ant Design 主题支持 - **WHEN** 配置 Ant Design 主题 - **THEN** 前端 SHALL 支持亮色和暗色模式切换 - **THEN** 前端 SHALL 使用 Ant Design v6 的 theme.darkAlgorithm 和 theme.defaultAlgorithm - **THEN** 前端 SHALL 通过 ConfigProvider 动态切换主题 ### Requirement: 样式体系 前端样式 SHALL 优先使用 Ant Design 样式体系,SCSS 作为补充工具。 #### Scenario: Ant Design 样式优先 - **WHEN** 实现组件样式 - **THEN** 前端 SHALL 优先使用 Ant Design 组件的 style prop - **THEN** 前端 SHALL 优先使用 Ant Design v6 的语义化样式(classNames 和 styles props) - **THEN** 前端 SHALL 使用 Ant Design Layout 组件处理布局 #### Scenario: SCSS 补充使用 - **WHEN** Ant Design 样式体系无法满足需求 - **THEN** 前端 MAY 使用 SCSS 作为补充 - **THEN** SCSS 文件 SHALL 使用 *.module.scss(SCSS Modules) - **THEN** 前端 SHALL NOT 使用纯 CSS 文件(*.css) #### Scenario: 移除冗余 SCSS - **WHEN** SCSS 文件仅实现 Ant Design 已有的功能 - **THEN** 前端 SHALL 移除该 SCSS 文件 - **THEN** 前端 SHALL 使用 Ant Design 内置功能替代 ### Requirement: 提供侧边栏导航 前端 SHALL 使用 Ant Design `Layout.Sider` 提供侧边栏导航。 #### Scenario: 侧边栏内容 - **WHEN** 渲染侧边栏 - **THEN** 侧边栏顶部 SHALL 显示应用名称/Logo - **THEN** 侧边栏 SHALL 包含 inline 模式的导航菜单 - **THEN** 导航菜单项 SHALL 包含:供应商管理(CloudServerOutlined 图标)、用量统计(BarChartOutlined 图标) - **THEN** 侧边栏底部 SHALL 放置主题切换按钮 #### Scenario: 侧边栏折叠 - **WHEN** 用户点击侧边栏折叠按钮 - **THEN** 侧边栏 SHALL 切换折叠/展开状态 - **THEN** 折叠状态下菜单项 SHALL 仅显示图标 - **THEN** 折叠状态下应用名称/Logo SHALL 隐藏或缩小 - **THEN** 折叠状态下主题切换按钮 SHALL 保持可见可点击 #### Scenario: 导航菜单交互 - **WHEN** 用户点击导航中的"供应商管理" - **THEN** 前端 SHALL 导航到 `/providers` 并高亮当前菜单项 - **WHEN** 用户点击导航中的"用量统计" - **THEN** 前端 SHALL 导航到 `/stats` 并高亮当前菜单项 ### Requirement: 提供导航 前端 SHALL 使用 React Router v7 提供导航。 #### Scenario: 路由配置 - **WHEN** 应用启动 - **THEN** 前端 SHALL 使用 React Router v7 Library 模式(BrowserRouter) - **THEN** `/providers` 路径 SHALL 显示供应商管理页面 - **THEN** `/stats` 路径 SHALL 显示用量统计页面 - **THEN** `/` 路径 SHALL 重定向到 `/providers` - **THEN** 不存在的路径 SHALL 显示 404 页面 #### Scenario: 导航菜单 - **WHEN** 用户点击导航中的"供应商管理" - **THEN** 前端 SHALL 导航到 `/providers` 并高亮当前菜单项 - **WHEN** 用户点击导航中的"用量统计" - **THEN** 前端 SHALL 导航到 `/stats` 并高亮当前菜单项 #### Scenario: URL 同步 - **WHEN** 用户在供应商页面刷新浏览器 - **THEN** 前端 SHALL 保持在供应商页面(URL 持久化) - **WHEN** 用户使用浏览器后退按钮 - **THEN** 前端 SHALL 正确导航到上一个页面 ### Requirement: 使用 React 和 TypeScript 前端 SHALL 使用 React 和 TypeScript 实现,遵循 strict 模式。 #### Scenario: TypeScript strict 模式 - **WHEN** 编写前端代码 - **THEN** TypeScript 配置 SHALL 开启 strict: true - **THEN** TypeScript 配置 SHALL 开启 noUncheckedIndexedAccess - **THEN** 所有代码 SHALL NOT 使用 any 类型 - **THEN** tsconfig SHALL 合并为单文件(不使用 project references) #### Scenario: React 函数组件 - **WHEN** 实现 UI - **THEN** 它 SHALL 使用 React 函数组件 - **THEN** 它 SHALL 使用自定义 Hooks 封装业务逻辑 ### Requirement: 使用 Vite 构建 前端 SHALL 使用 Vite 作为构建工具。 #### Scenario: 开发服务器 - **WHEN** 在开发模式下启动前端 - **THEN** Vite SHALL 使用热模块替换服务应用 #### Scenario: 生产构建 - **WHEN** 为生产构建前端 - **THEN** Vite SHALL 生成优化的静态文件 ### Requirement: 与后端 API 通信 前端 SHALL 使用 TanStack Query v5 和统一 API 客户端与后端通信。 #### Scenario: API 基础 URL 配置 - **WHEN** 前端发起 API 请求 - **THEN** 开发环境 SHALL 通过 Vite proxy 转发 /api 请求到后端 - **THEN** 生产环境 SHALL 使用环境变量 VITE_API_BASE 配置基础 URL - **THEN** 前端 SHALL NOT 硬编码 API 基础 URL #### Scenario: 统一 API 客户端 - **WHEN** 进行 API 调用 - **THEN** 所有调用 SHALL 通过 api/client.ts 的 request() 方法 - **THEN** 错误处理 SHALL 统一抛出 ApiError(包含 status 和 message) - **THEN** 开发环境 SHALL 使用 Vite proxy 转发 API 请求 #### Scenario: 字段名转换 - **WHEN** 接收后端 API 响应 - **THEN** API 层 SHALL 将 snake_case 字段转换为 camelCase - **WHEN** 发送请求到后端 API - **THEN** API 层 SHALL 将 camelCase 字段转换为 snake_case - **THEN** hooks 和组件 SHALL 仅使用 camelCase 字段 #### Scenario: TanStack Query 数据管理 - **WHEN** 页面加载数据 - **THEN** 前端 SHALL 使用 TanStack Query 的 useQuery hook - **THEN** 前端 SHALL 自动缓存请求结果 - **THEN** 前端 SHALL 自动处理加载和错误状态 #### Scenario: TanStack Query 写操作 - **WHEN** 用户执行创建、更新或删除操作 - **THEN** 前端 SHALL 使用 TanStack Query 的 useMutation hook - **THEN** 操作成功后 SHALL 自动失效相关查询缓存 - **THEN** 操作失败 SHALL 使用 Ant Design message.error() 显示错误提示 #### Scenario: 错误提示 - **WHEN** API 请求失败(网络错误、4xx、5xx) - **THEN** 前端 SHALL 使用 Ant Design 的 message.error() 显示全局错误提示 - **THEN** 错误消息 SHALL 具有描述性