1
0
Files
nex/openspec/specs/frontend/spec.md
lanyuanxiaoyao 5ae9d85272 style: 优化前端样式,提升现代化设计感
- ConfigProvider 注入全局配置(动画、表格尺寸)
- CSS Variables 主题微调(页面背景、圆角、字体栈)
- AppLayout Menu 支持 logo/operations/collapsed
- Statistic 组件增加 color/prefix/suffix/animation
- Card 组件启用 hoverShadow/headerBordered
- Table 组件启用 stripe 斑马纹
- Tag 组件使用 variant="light" + shape="round"
- Dialog 居中显示并设置固定宽度
- 布局样式硬编码颜色替换为 TDesign Token
- UsageChart 改用 AreaChart + 渐变填充
- 更新 frontend spec 同步样式体系要求
2026-04-22 18:09:22 +08:00

21 KiB
Raw Blame History

前端配置界面

Purpose

TBD - 提供供应商、模型配置和用量统计的前端管理界面

Requirements

Requirement: 样式体系

前端样式 SHALL 优先使用 TDesign 样式体系SCSS 作为补充工具。

Scenario: TDesign 组件 Props 优先

  • WHEN 实现组件视觉效果
  • THEN 前端 SHALL 优先使用 TDesign 组件的视觉增强 Props如 color、trend、hoverShadow、stripe、variant、shape 等)
  • THEN 前端 SHALL NOT 通过 CSS 类名覆盖组件内部样式

Scenario: CSS Variables 主题微调

  • WHEN 需要调整全局视觉风格
  • THEN 前端 SHALL 通过 `:root` 中声明 TDesign CSS Variables`--td-*`)进行覆盖
  • THEN 前端 SHALL NOT 使用 `!important` 或高优先级选择器覆盖组件样式

Scenario: 布局样式 Token 化

  • WHEN 编写布局级 inline style
  • THEN 前端 SHALL 使用 TDesign CSS Token 引用(`var(--td-*)`)替代硬编码颜色值
  • THEN 前端 SHALL NOT 在布局样式中硬编码 `#fff`、`#e7e7e7`、`#999` 等颜色值

Scenario: SCSS 补充使用

  • WHEN TDesign 样式体系无法满足需求
  • THEN 前端 MAY 使用 SCSS 作为补充
  • THEN SCSS 文件 SHALL 仅用于 `:root` 级别的 CSS Variables 声明和全局 reset
  • THEN 前端 SHALL NOT 使用纯 CSS 文件(*.css

Requirement: 提供统计查看页面

前端 SHALL 使用 TDesign 组件提供统计仪表盘页面。

Scenario: 显示统计概览

  • WHEN 加载统计页面
  • THEN 前端 SHALL 在顶部显示统计摘要卡片(总请求量、活跃模型数、活跃供应商数、今日请求量)
  • THEN 统计摘要数据 SHALL 从 stats API 返回数据中前端聚合
  • THEN 每个 Statistic 组件 SHALL 使用 `color` prop 设置预设颜色风格
  • THEN 每个 Statistic 组件 SHALL 使用 `prefix` prop 显示图标前缀
  • THEN 每个 Statistic 组件 SHALL 使用 `suffix` prop 显示单位文字
  • THEN Statistic 组件首次加载 SHALL 使用 `animation` prop 展示数字滚动动画
  • THEN Card 组件 SHALL 设置 `bordered={false}` 和 `hoverShadow`
  • THEN 前端 SHALL 显示请求趋势折线图
  • THEN 趋势图表卡片 SHALL 设置 `headerBordered`
  • THEN 前端 SHALL 使用 TDesign Table 显示统计数据
  • THEN 统计数据 SHALL 按供应商和模型显示请求计数

Scenario: 统计表格列宽约束

  • WHEN 渲染统计表格
  • THEN 供应商列 SHALL 固定宽度 180px 并启用 ellipsis + Tooltip
  • THEN 模型列 SHALL 固定宽度 250px 并启用 ellipsis + Tooltip
  • THEN 日期列 SHALL 固定宽度 120px
  • THEN 请求数列 SHALL 固定宽度 100px 并右对齐

Scenario: 统计表格空状态

  • WHEN 统计数据为空
  • THEN 表格 SHALL 显示自定义空状态文案 "暂无统计数据"

Scenario: 按供应商过滤统计

  • WHEN 用户从 TDesign Select 选择供应商
  • THEN 前端 SHALL 自动查询并过滤统计
  • THEN 统计摘要卡片和趋势图表 SHALL 同步更新

Scenario: 按日期范围过滤统计

  • WHEN 用户使用 TDesign DateRangePicker 选择日期范围
  • THEN 前端 SHALL 自动查询并过滤统计
  • THEN 统计摘要卡片和趋势图表 SHALL 同步更新

Scenario: 仪表盘区域排列

  • WHEN 渲染统计页面
  • THEN 页面 SHALL 按以下顺序从上到下排列:统计摘要卡片、趋势图表、筛选栏和数据表格
  • THEN 各区域之间 SHALL 有合理的垂直间距
  • THEN 筛选栏和数据表格 SHALL 保持在同一个卡片中

Scenario: 数据联动

  • WHEN 用户通过筛选栏修改筛选条件
  • THEN 统计摘要卡片和趋势图表 SHALL 随筛选条件变化更新
  • THEN 数据表格 SHALL 同步更新
  • THEN 所有区域 SHALL 共享同一份筛选后的数据

Requirement: 提供供应商管理页面

前端 SHALL 使用 TDesign 组件提供供应商管理页面。

Scenario: 显示供应商列表

  • WHEN 加载供应商管理页面
  • THEN 前端 SHALL 使用 TDesign Table 显示所有已配置供应商
  • THEN Table SHALL 启用 `stripe`(斑马纹)和 `hover`(行悬浮高亮)
  • THEN 每个供应商 SHALL 显示 name、base_url 和 enabled 状态(使用 Tag 组件)
  • THEN 状态 Tag SHALL 使用 `variant="light"` 和 `shape="round"`
  • THEN 协议 Tag SHALL 使用 `variant="light"` 和 `shape="round"`
  • THEN API Key SHALL 显示完整值(不进行掩码处理)
  • THEN 表格 SHALL 支持展开行以显示关联模型
  • THEN Card 组件 SHALL 设置 `hoverShadow` 和 `headerBordered`

Scenario: 表格列宽约束

  • WHEN 渲染供应商表格
  • THEN 名称列 SHALL 固定宽度 180px 并启用 ellipsis超长文本显示省略号hover 显示 Tooltip
  • THEN Base URL 列 SHALL 不设固定宽度(浮动填充剩余空间)并启用 ellipsis + Tooltip
  • THEN API Key 列 SHALL 不设固定宽度(浮动填充剩余空间)并启用 ellipsis + Tooltip
  • THEN 状态列 SHALL 固定宽度 80px
  • THEN 操作列 SHALL 固定宽度 160px

Scenario: 表格空状态

  • WHEN 供应商列表为空
  • THEN 表格 SHALL 显示自定义空状态文案 "暂无供应商,点击上方按钮添加"

Scenario: 添加新供应商

  • WHEN 用户点击"添加供应商"按钮
  • THEN 前端 SHALL 使用 TDesign Dialog + Form 显示输入表单
  • THEN Dialog SHALL 使用 `placement="center"` 居中显示
  • THEN Dialog SHALL 设置 `width="520px"`
  • THEN 表单 SHALL 包含 id、name、api_key、base_url 字段,带校验规则
  • THEN Dialog SHALL 禁用蒙版点击关闭closeOnOverlayClick={false}
  • THEN Dialog SHALL 禁用 ESC 键关闭closeOnEscKeydown={false}
  • THEN Dialog SHALL 设置 lazy={false} 禁用懒加载
  • WHEN 用户提交包含有效数据的表单
  • THEN 前端 SHALL 通过 mutateAsync 调用创建 API
  • THEN 成功后 SHALL 关闭 Dialog 并刷新供应商列表
  • THEN 失败 SHALL 保持 Dialog 打开并显示错误提示MessagePlugin.error

Scenario: 编辑现有供应商

  • WHEN 用户点击供应商的"编辑"按钮
  • THEN 前端 SHALL 使用 TDesign Dialog + Form 显示预填充数据的表单
  • THEN Dialog SHALL 使用 `placement="center"` 居中显示
  • THEN Dialog SHALL 设置 `width="520px"`
  • THEN API Key SHALL 回显当前值(完整值)
  • THEN API Key 输入框 SHALL 为普通文本输入(不使用 password 类型)
  • THEN API Key 字段 SHALL 始终为必填
  • THEN Dialog SHALL 禁用蒙版点击关闭closeOnOverlayClick={false}
  • THEN Dialog SHALL 禁用 ESC 键关闭closeOnEscKeydown={false}
  • THEN Dialog SHALL 设置 lazy={false} 禁用懒加载
  • WHEN 用户提交包含更新数据的表单
  • THEN 前端 SHALL 通过 mutateAsync 调用更新 API
  • THEN 成功后 SHALL 关闭 Dialog 并刷新供应商列表
  • THEN 失败 SHALL 保持 Dialog 打开并显示错误提示MessagePlugin.error

Scenario: 删除供应商

  • WHEN 用户点击供应商的"删除"按钮
  • THEN 前端 SHALL 使用 TDesign Popconfirm 弹出确认
  • WHEN 用户确认删除
  • THEN 前端 SHALL 通过 useMutation 调用删除 API
  • THEN 成功后 SHALL 刷新供应商列表

Requirement: 提供模型管理界面

前端 SHALL 在供应商页面展开行中提供模型管理。

Scenario: 显示供应商的模型

  • WHEN 展开供应商行
  • THEN 前端 SHALL 显示该供应商的模型列表
  • THEN Table SHALL 启用 `stripe`(斑马纹)和 `hover`(行悬浮高亮)
  • THEN 每个模型 SHALL 显示 model_name 和 enabled 状态
  • THEN 状态 Tag SHALL 使用 `variant="light"` 和 `shape="round"`
  • THEN 模型名称列 SHALL 启用 ellipsis超长文本显示省略号hover 显示 Tooltip

Scenario: 模型表格空状态

  • WHEN 模型列表为空
  • THEN 表格 SHALL 显示自定义空状态文案 "暂无模型,点击上方按钮添加"

Scenario: 为供应商添加模型

  • WHEN 用户在展开行中点击"添加模型"
  • THEN 前端 SHALL 显示 TDesign Dialog + Form
  • THEN Dialog SHALL 使用 `placement="center"` 居中显示
  • THEN Dialog SHALL 设置 `width="520px"`
  • THEN provider_id SHALL 自动关联当前供应商
  • THEN 供应商选择 SHALL 使用 `options` 属性
  • THEN 创建表单 SHALL NOT 包含 ID 输入框(后端自动生成 UUID
  • THEN Dialog SHALL 禁用蒙版点击关闭closeOnOverlayClick={false}
  • THEN Dialog SHALL 禁用 ESC 键关闭closeOnEscKeydown={false}
  • WHEN 用户提交表单
  • THEN 前端 SHALL 通过 mutateAsync 调用创建 API
  • THEN 成功后 SHALL 关闭 Dialog 并刷新模型列表
  • THEN 失败 SHALL 保持 Dialog 打开并显示错误提示MessagePlugin.error

Scenario: 编辑模型

  • WHEN 用户点击模型的"编辑"
  • THEN 前端 SHALL 显示编辑表单
  • THEN Dialog SHALL 使用 `placement="center"` 居中显示
  • THEN Dialog SHALL 设置 `width="520px"`
  • THEN 编辑表单 SHALL NOT 包含统一模型 ID 字段
  • THEN Dialog SHALL 禁用蒙版点击关闭closeOnOverlayClick={false}
  • THEN Dialog SHALL 禁用 ESC 键关闭closeOnEscKeydown={false}
  • THEN Dialog SHALL 设置 lazy={false} 禁用懒加载
  • WHEN 用户提交表单
  • THEN 前端 SHALL 通过 mutateAsync 调用更新 API
  • THEN 成功后 SHALL 关闭 Dialog 并刷新模型列表
  • THEN 失败 SHALL 保持 Dialog 打开并显示错误提示MessagePlugin.error

Scenario: 删除模型

  • WHEN 用户点击模型的"删除"
  • THEN 前端 SHALL 使用 Popconfirm 弹出确认
  • WHEN 用户确认删除
  • THEN 前端 SHALL 通过 useMutation 调用删除 API
  • THEN 成功后 SHALL 刷新模型列表

Requirement: 提供响应式布局

前端 SHALL 使用 TDesign Layout 提供侧边栏导航布局。

Scenario: 桌面布局

  • WHEN 在桌面屏幕上查看前端
  • THEN 布局 SHALL 使用 TDesign `Layout.Aside` + `Menu`
  • THEN 侧边栏 SHALL 显示导航菜单,包含图标和文字标签
  • THEN 侧边栏 SHALL 使用固定宽度 232px
  • THEN Menu 组件 SHALL 使用 `logo` prop 显示品牌标识
  • THEN Menu 组件 SHALL 使用 `operations` prop 在底部显示操作区域
  • THEN Menu 组件 SHALL 支持 `collapsed` 折叠功能

Scenario: 页面内容区域

  • WHEN 显示页面内容
  • THEN 内容区域 SHALL 在 `Layout.Content` 中渲染
  • THEN 页面之间 SHALL 通过 React Router Outlet 渲染

Scenario: Header 区域

  • WHEN 渲染页面 Header
  • THEN Header SHALL 仅显示当前页面标题
  • THEN Header SHALL 不包含导航菜单
  • THEN Header 背景色 SHALL 使用 `var(--td-bg-color-container)` Token
  • THEN Header 底部分割线 SHALL 使用 `var(--td-component-stroke)` Token

Requirement: 显示协议字段

前端 SHALL 在供应商管理界面显示协议字段。

Scenario: 供应商表格显示协议列

  • WHEN 渲染供应商表格
  • THEN 表格 SHALL 包含协议列
  • THEN 协议列 SHALL 显示 "OpenAI" 或 "Anthropic" 标签
  • THEN 标签 SHALL 使用 `variant="light"` 和 `shape="round"`
  • THEN OpenAI 协议 SHALL 使用主题色标签
  • THEN Anthropic 协议 SHALL 使用成功色标签

Scenario: 供应商表单选择协议

  • WHEN 创建或编辑供应商
  • THEN 表单 SHALL 包含协议选择下拉框
  • THEN 下拉框 SHALL 提供 "OpenAI" 和 "Anthropic" 选项
  • THEN 协议字段 SHALL 为必填项

Requirement: 使用 TDesign UI 组件库

前端 SHALL 使用 TDesign 作为 UI 组件库。

Scenario: 全局配置

  • WHEN 应用启动
  • THEN ConfigProvider SHALL 注入全局配置
  • THEN 全局配置 SHALL 包含 `animation` 配置ripple、expand、fade 动画开启)
  • THEN 全局配置 SHALL 包含 `table.size` 默认尺寸设置

Requirement: 主题定制

前端 SHALL 通过 TDesign CSS Variables 进行主题微调。

Scenario: 页面背景色

  • WHEN 渲染页面
  • THEN `:root` SHALL 设置 `--td-bg-color-page` 为 `#f5f7fa`

Scenario: 圆角调整

  • WHEN 渲染组件
  • THEN `:root` SHALL 设置 `--td-radius-default` 为 `6px`
  • THEN `:root` SHALL 设置 `--td-radius-medium` 为 `9px`
  • THEN `:root` SHALL 设置 `--td-radius-large` 为 `12px`
  • THEN `:root` SHALL 设置 `--td-radius-extraLarge` 为 `16px`

Scenario: 字体栈声明

  • WHEN 渲染页面
  • THEN `:root` SHALL 设置 `--td-font-family` 为系统字体栈(-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto 等)

Requirement: 提供请求趋势图表

前端 SHALL 使用 Recharts 提供请求趋势可视化。

Scenario: 显示面积图表

  • WHEN 渲染请求趋势图表
  • THEN 前端 SHALL 使用 Recharts AreaChart + Area 组件(替代 LineChart + Line
  • THEN 面积填充 SHALL 使用线性渐变(从品牌色到透明)
  • THEN 图表 SHALL 仅使用 Recharts 组件 Props API 定制样式
  • THEN 前端 SHALL NOT 通过 CSS 覆盖 Recharts 内部样式类名

Scenario: 图表加载态

  • WHEN 统计数据加载中
  • THEN UsageChart 的 Card 组件 SHALL 显示骨架屏loading prop
  • THEN StatsPage SHALL 向 UsageChart 传递 isLoading 状态

Requirement: 提供 404 页面

前端 SHALL 提供页面未找到的 404 页面。

Scenario: 显示 404 页面

  • WHEN 用户访问不存在的路由
  • THEN 前端 SHALL 显示 404 页面
  • THEN 404 标题颜色 SHALL 使用 `var(--td-text-color-placeholder)` Token
  • THEN 描述文字颜色 SHALL 使用 `var(--td-text-color-secondary)` Token

Requirement: 提供设置页面

前端 SHALL 提供设置页面。

Scenario: 显示设置页面

  • WHEN 用户访问设置页面
  • THEN 前端 SHALL 显示设置页面
  • THEN 开发中提示文字颜色 SHALL 使用 `var(--td-text-color-placeholder)` Token

Requirement: 显示统一模型 ID

前端 SHALL 在所有显示模型的地方使用统一模型 ID。

Scenario: 模型表格显示统一 ID 列

  • WHEN 渲染模型表格
  • THEN 表格 SHALL 包含统一模型 ID 列
  • THEN 统一模型 ID 列 SHALL 显示 `provider_id/model_name` 格式
  • THEN 统一模型 ID 列 SHALL 启用 ellipsis超长文本显示省略号hover 显示 Tooltip
  • THEN 统一模型 ID 列 SHALL 固定宽度 250px

Scenario: 统一模型 ID 降级显示

  • WHEN 后端未返回 unified_id 字段
  • THEN 前端 SHALL 拼接 providerId 和 modelName 显示
  • THEN 拼接格式 SHALL 为 `{providerId}/{modelName}`

Requirement: 提取并映射错误码

前端 SHALL 提取后端结构化错误响应中的错误码并映射为友好消息。

Scenario: API 客户端提取错误码

  • WHEN 后端返回结构化错误响应 `{error: string, code: string}`
  • THEN API 客户端 SHALL 提取 code 字段
  • THEN ApiError 对象 SHALL 包含 code 字段
  • THEN code 字段 SHALL 为可选(兼容旧错误格式)

Scenario: Hooks 映射错误码为中文消息

  • WHEN 处理 API 错误
  • THEN Hooks SHALL 使用错误码映射表
  • THEN 映射表 SHALL 包含以下错误码:
    • `duplicate_model` → "同一供应商下模型名称已存在"
    • `invalid_provider_id` → "供应商 ID 仅允许字母、数字、下划线,长度 1-64"
    • `immutable_field` → "供应商 ID 不允许修改"
  • THEN 未定义的错误码 SHALL 降级使用原始错误消息

Requirement: 优雅处理 API 错误

前端 SHALL 处理 API 错误并显示用户友好的消息。

Scenario: API 请求失败

  • WHEN API 请求失败网络错误、4xx、5xx
  • THEN 前端 SHALL 显示全局错误提示
  • THEN 错误消息 SHALL 具有描述性

Scenario: 验证错误

  • WHEN 用户提交包含无效数据的表单
  • THEN 前端 SHALL 在相关字段旁显示验证错误
  • THEN 前端 SHALL 阻止表单提交

Requirement: 提供侧边栏导航

前端 SHALL 使用 TDesign `Layout.Aside` 提供侧边栏导航。

Scenario: 侧边栏内容

  • WHEN 渲染侧边栏
  • THEN 侧边栏顶部 SHALL 显示应用名称/Logo
  • THEN 侧边栏 SHALL 包含导航菜单
  • THEN 导航菜单项 SHALL 包含供应商管理ServerIcon 图标、用量统计ChartLineIcon 图标、设置SettingIcon 图标)

Scenario: 导航菜单交互

  • WHEN 用户点击导航中的"供应商管理"
  • THEN 前端 SHALL 导航到 `/providers` 并高亮当前菜单项
  • WHEN 用户点击导航中的"用量统计"
  • THEN 前端 SHALL 导航到 `/stats` 并高亮当前菜单项
  • WHEN 用户点击导航中的"设置"
  • THEN 前端 SHALL 导航到 `/settings` 并高亮当前菜单项

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 19 适配器

前端 SHALL 导入 TDesign react-19-adapter 以支持 React 19。

Scenario: 导入适配器

  • WHEN 应用启动
  • THEN main.tsx SHALL 导入 'tdesign-react/es/_util/react-19-adapter'
  • THEN MessagePlugin、DialogPlugin 等插件式调用 SHALL 正常工作

Scenario: 错误提示显示

  • WHEN API 请求失败
  • THEN MessagePlugin.error SHALL 正确渲染错误提示
  • THEN 错误提示 SHALL 显示在页面顶部placement: top
  • THEN 错误提示 SHALL 在 3 秒后自动消失

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 显示错误提示

Scenario: 错误提示

  • WHEN API 请求失败网络错误、4xx、5xx
  • THEN 前端 SHALL 显示全局错误提示
  • THEN 错误消息 SHALL 具有描述性