306 lines
8.2 KiB
Markdown
306 lines
8.2 KiB
Markdown
# 前端 API 规范
|
||
|
||
## 概述
|
||
|
||
前端 API 层封装所有 HTTP 请求,与后端接口一一对应。API 文件位于 `ui/src/api/` 目录,按模块分组,使用封装后的 `VAxios` 发送请求。
|
||
|
||
:::tip 设计原则
|
||
- 每个后端模块对应一个 API 文件
|
||
- 函数命名统一使用 `名词 + 动词` 格式(与后端保持一致)
|
||
- 请求路径使用相对路径(`/position/page`),不含 `/api/v1` 前缀(由 Axios baseURL 统一拼接)
|
||
- 统一通过 `http.request()` 发送请求
|
||
:::
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
ui/src/api/
|
||
├── common/ # 公共 API(上传、字典按编码查询、城市、模板下载)
|
||
│ ├── index.ts
|
||
│ ├── menu.ts
|
||
│ ├── user.ts
|
||
│ └── city.ts
|
||
├── system/ # 系统模块
|
||
│ ├── user.ts
|
||
│ ├── role.ts
|
||
│ ├── menu.ts
|
||
│ ├── dept.ts
|
||
│ ├── position.ts
|
||
│ ├── level.ts
|
||
│ ├── dictionary.ts
|
||
│ ├── loginLog.ts
|
||
│ ├── operLog.ts
|
||
│ └── tenant.ts
|
||
├── data/ # 数据模块
|
||
│ ├── param.ts
|
||
│ ├── config.ts
|
||
│ ├── dictionary.ts
|
||
│ ├── notice.ts
|
||
│ └── city.ts
|
||
├── content/ # 内容模块
|
||
│ ├── article.ts
|
||
│ ├── category.ts
|
||
│ └── link.ts
|
||
├── monitor/ # 监控模块
|
||
│ └── job.ts
|
||
├── file/ # 文件模块
|
||
│ └── fileTemplate.ts
|
||
├── tool/ # 工具模块
|
||
│ ├── generator.ts
|
||
│ └── example.ts
|
||
├── setting/ # 设置模块
|
||
│ ├── profile.ts
|
||
│ └── web.ts
|
||
├── region/ # 区域模块
|
||
│ └── region.ts
|
||
└── dashboard/ # 仪表盘
|
||
├── console.ts
|
||
└── message.ts
|
||
```
|
||
|
||
## 函数命名规范
|
||
|
||
| 操作 | 命名格式 | 示例 | HTTP 方法 |
|
||
|------|---------|------|----------|
|
||
| 分页查询 | `getXxxList` 或 `getXxxPage` | `getPositionList` | GET |
|
||
| 全量列表 | `getXxxAllList` | `getPositionAllList` | GET |
|
||
| 详情查询 | `getXxxDetail` | `getPositionDetail` | GET |
|
||
| 添加 | `xxxAdd` | `positionAdd` | POST |
|
||
| 编辑 | `xxxUpdate` | `positionUpdate` | PUT |
|
||
| 删除 | `xxxDelete` | `positionDelete` | DELETE |
|
||
| 批量删除 | `xxxBatchDelete` | `positionBatchDelete` | DELETE |
|
||
| 导入 | `xxxImport` | `levelImport` | POST |
|
||
| 导出 | `xxxExport` | `levelExport` | GET |
|
||
|
||
:::warning 命名风格
|
||
实际代码中采用 `positionAdd` 而非 `addPosition`(名词在前、动词在后),与后端 Python 函数命名风格一致。
|
||
:::
|
||
|
||
## API 文件标准模板
|
||
|
||
以岗位管理(`api/system/position.ts`)为标准:
|
||
|
||
```typescript
|
||
import { http } from '@/utils/http/axios';
|
||
|
||
/**
|
||
* @description: 岗位列表(分页)
|
||
*/
|
||
export function getPositionList(params?) {
|
||
return http.request({
|
||
url: '/position/page',
|
||
method: 'GET',
|
||
params,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 获取全部岗位列表(不分页)
|
||
* @param params 参数
|
||
* @returns 返回结果
|
||
*/
|
||
export function getPositionAllList(params?) {
|
||
return http.request({
|
||
url: '/position/list',
|
||
method: 'GET',
|
||
params,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @description: 根据ID获取详情
|
||
*/
|
||
export function getPositionDetail(positionId) {
|
||
return http.request({
|
||
url: '/position/detail/' + positionId,
|
||
method: 'get',
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @description: 添加岗位
|
||
*/
|
||
export function positionAdd(data: any) {
|
||
return http.request({
|
||
url: '/position/add',
|
||
method: 'POST',
|
||
data,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @description: 更新岗位
|
||
*/
|
||
export function positionUpdate(data: any) {
|
||
return http.request({
|
||
url: '/position/update',
|
||
method: 'PUT',
|
||
data,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @description: 删除岗位
|
||
*/
|
||
export function positionDelete(positionId) {
|
||
return http.request({
|
||
url: '/position/delete/' + positionId,
|
||
method: 'DELETE',
|
||
});
|
||
}
|
||
|
||
/**
|
||
* @description: 批量删除岗位
|
||
*/
|
||
export function positionBatchDelete(data: any) {
|
||
return http.request({
|
||
url: '/position/batchDelete',
|
||
method: 'DELETE',
|
||
data,
|
||
});
|
||
}
|
||
```
|
||
|
||
## 完整示例:用户模块
|
||
|
||
```typescript
|
||
// api/system/user.ts
|
||
import { http } from '@/utils/http/axios';
|
||
|
||
export interface BasicResponseModel<T = any> {
|
||
code: number;
|
||
msg: string;
|
||
data: T;
|
||
}
|
||
|
||
export interface BasicPageParams {
|
||
pageNo: number;
|
||
pageSize: number;
|
||
total: number;
|
||
}
|
||
|
||
/** @description: 获取用户列表 */
|
||
export function getUserList(params) {
|
||
return http.request({ url: '/user/page', method: 'get', params });
|
||
}
|
||
|
||
/** @description: 根据ID获取详情 */
|
||
export function getUserDetail(userId) {
|
||
return http.request({ url: '/user/detail/' + userId, method: 'get' });
|
||
}
|
||
|
||
/** @description: 添加用户 */
|
||
export function userAdd(data: any) {
|
||
return http.request({ url: '/user/add', method: 'POST', data });
|
||
}
|
||
|
||
/** @description: 更新用户 */
|
||
export function userUpdate(data: any) {
|
||
return http.request({ url: '/user/update', method: 'PUT', data });
|
||
}
|
||
|
||
/** @description: 删除用户 */
|
||
export function userDelete(userId) {
|
||
return http.request({ url: '/user/delete/' + userId, method: 'DELETE' });
|
||
}
|
||
|
||
/** @description: 批量删除用户 */
|
||
export function userBatchDelete(data: any) {
|
||
return http.request({ url: '/user/batchDelete', method: 'DELETE', data });
|
||
}
|
||
|
||
/** @description: 重置密码 */
|
||
export function resetPwd(data: any) {
|
||
return http.request({ url: '/user/resetPwd', method: 'PUT', data });
|
||
}
|
||
|
||
/** @description: 导出用户 */
|
||
export function userExport(params) {
|
||
return http.request({ url: '/user/export', method: 'GET' });
|
||
}
|
||
```
|
||
|
||
## 请求路径规则
|
||
|
||
URL 使用相对路径,不含 `/api/v1` 前缀(由 Axios 实例的 `baseURL` 统一拼接):
|
||
|
||
| 后端路由 | 前端 URL | 说明 |
|
||
|----------|----------|------|
|
||
| `GET /api/v1/position/page` | `/position/page` | baseURL 已含 `/api/v1` |
|
||
| `GET /api/v1/position/detail/{id}` | `/position/detail/` + id | 路径参数拼接 |
|
||
| `POST /api/v1/position/add` | `/position/add` | - |
|
||
| `PUT /api/v1/position/update` | `/position/update` | - |
|
||
| `DELETE /api/v1/position/delete/{id}` | `/position/delete/` + id | - |
|
||
| `DELETE /api/v1/position/batchDelete` | `/position/batchDelete` | body 传 ID 数组 |
|
||
|
||
## params 与 data 区别
|
||
|
||
| 参数 | 适用方法 | 说明 |
|
||
|------|----------|------|
|
||
| `params` | GET | query 参数,拼接到 URL 后面 |
|
||
| `data` | POST / PUT / DELETE | body 参数,放在请求体中 |
|
||
|
||
```typescript
|
||
// GET 请求:params 拼到 URL
|
||
http.request({ url: '/position/page', method: 'GET', params: { pageNo: 1, pageSize: 10 } });
|
||
// 实际请求: /api/v1/position/page?pageNo=1&pageSize=10
|
||
|
||
// POST 请求:data 放 body
|
||
http.request({ url: '/position/add', method: 'POST', data: { name: '测试', status: 1 } });
|
||
// 实际请求: /api/v1/position/add body: {"name":"测试","status":1}
|
||
```
|
||
|
||
## 公共 API
|
||
|
||
公共 API 位于 `api/common/index.ts`,包含跨模块复用的接口:
|
||
|
||
```typescript
|
||
import { http } from '@/utils/http/axios';
|
||
|
||
/** 本地文件上传 */
|
||
export function upload(data) {
|
||
return http.request({ url: '/upload/uploadFile', method: 'post', data });
|
||
}
|
||
|
||
/** 根据字典编码查询字典项 */
|
||
export function getDictItemByCode(code) {
|
||
return http.request({ url: '/dict/item/getDictItemList/' + code, method: 'GET' });
|
||
}
|
||
|
||
/** 下载模板 */
|
||
export function getTemplateByCode(code: any) {
|
||
return http.request({ url: '/file/template/getTemplateByCode/' + code, method: 'GET' });
|
||
}
|
||
```
|
||
|
||
## 响应格式
|
||
|
||
后端统一返回 `{code, data, msg, ok}` 格式:
|
||
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"data": { "records": [...], "total": 100 },
|
||
"msg": "操作成功",
|
||
"ok": true
|
||
}
|
||
```
|
||
|
||
前端 Axios 拦截器自动处理:
|
||
- `ok: true` → 返回 `res.data`
|
||
- `ok: false` → 弹出 `res.msg` 错误提示
|
||
- `code: 401` → token 失效,跳转登录页
|
||
|
||
页面中无需手动判断,直接使用返回值:
|
||
|
||
```typescript
|
||
const loadDataTable = async (res: any) => {
|
||
const result = await getPositionList({ ...formParams, ...res });
|
||
return result; // BasicTable 自动处理分页数据
|
||
};
|
||
```
|
||
|
||
## 总结
|
||
|
||
前端 API 规范:每个后端模块对应一个 API 文件,函数命名使用 `名词+动词` 格式(`positionAdd` / `positionDelete`)。URL 使用相对路径(不含 `/api/v1` 前缀),GET 用 `params`,POST/PUT/DELETE 用 `data`。统一通过 `http.request()` 发送请求,响应拦截器自动处理错误。
|