You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RuoYi-Vue/docs/architecture/api-interaction-spec.md

591 lines
23 KiB

# RuoYi-Vue 前后端交互规范
> 文档版本v1.0 | 生成日期2026-06-28 | 适用范围RuoYi-Vue 全项目
---
## 1. API 接口清单
### 1.1 接口总览
项目共包含 **35 个前端 API 模块文件****19 个后端 Controller**,梳理出 **约 180+ 个 API 端点**。
### 1.2 按模块分类
#### 1.2.1 系统管理模块system
| 序号 | 模块 | 前端 API 文件 | 后端 Controller | 接口数 | 基础路径 |
|------|------|--------------|-----------------|--------|----------|
| 1 | 用户管理 | `system/user.js` | `SysUserController` | 13 | `/system/user` |
| 2 | 角色管理 | `system/role.js` | `SysRoleController` | 11 | `/system/role` |
| 3 | 菜单管理 | `system/menu.js` | `SysMenuController` | 7 | `/system/menu` |
| 4 | 部门管理 | `system/dept.js` | `SysDeptController` | 8 | `/system/dept` |
| 5 | 岗位管理 | `system/post.js` | `SysPostController` | 5 | `/system/post` |
| 6 | 字典类型 | `system/dict/type.js` | `SysDictTypeController` | 7 | `/system/dict/type` |
| 7 | 字典数据 | `system/dict/data.js` | `SysDictDataController` | 6 | `/system/dict/data` |
| 8 | 参数配置 | `system/config.js` | `SysConfigController` | 7 | `/system/config` |
| 9 | 公告管理 | `system/notice.js` | `SysNoticeController` | 5 | `/system/notice` |
**系统管理模块小计69 个接口**
#### 1.2.2 监控模块monitor
| 序号 | 模块 | 前端 API 文件 | 后端 Controller | 接口数 | 基础路径 |
|------|------|--------------|-----------------|--------|----------|
| 1 | 在线用户 | `monitor/online.js` | `SysUserOnlineController` | 2 | `/monitor/online` |
| 2 | 登录日志 | `monitor/logininfor.js` | `SysLogininforController` | 3 | `/monitor/logininfor` |
| 3 | 操作日志 | `monitor/operlog.js` | `SysOperlogController` | 3 | `/monitor/operlog` |
| 4 | 服务监控 | `monitor/server.js` | `ServerController` | 1 | `/monitor/server` |
| 5 | 缓存监控 | `monitor/cache.js` | `CacheController` | 1 | `/monitor/cache` |
| 6 | 定时任务 | `monitor/job.js` | `SysJobController` | 7 | `/monitor/job` |
| 7 | 任务日志 | `monitor/jobLog.js` | `SysJobLogController` | 3 | `/monitor/jobLog` |
**监控模块小计20 个接口**
#### 1.2.3 业务模块 — 记账系统booksystem
| 序号 | 模块 | 前端 API 文件 | 后端 Controller | 接口数 | 基础路径 |
|------|------|--------------|-----------------|--------|----------|
| 1 | 交易账户 | `booksystem/account.js` | `AccountController` | 5 | `/booksystem/account` |
| 2 | 交易记账 | `booksystem/book.js` | `AccountBookController` | 5 | `/booksystem/book` |
| 3 | 当日操作 | `booksystem/operations.js` | `OperationsController` | 5 | `/booksystem/operations` |
| 4 | 单笔统计 | `booksystem/statistics.js` | `StatisticsController` | 5 | `/booksystem/statistics` |
| 5 | 持仓统计 | `booksystem/statistictotal.js` | `StatisticsTotalController` | 5 | `/booksystem/statistictotal` |
| 6 | 当日持仓 | `booksystem/statisticremain.js` | `StatisticsRemainController` | 5 | `/booksystem/statisticremain` |
**记账系统模块小计30 个接口**
#### 1.2.4 业务模块 — 股票系统stocksystem
| 序号 | 模块 | 前端 API 文件 | 后端 Controller | 接口数 | 基础路径 |
|------|------|--------------|-----------------|--------|----------|
| 1 | 行情数据 | `stocksystem/stocks.js` | `StocksController` | 6 (+16 扩展) | `/stocksystem/stocks` |
| 2 | 基础数据 | `stocksystem/stockbasic.js` | `StockBasicController` | 5 | `/stocksystem/stockbasic` |
| 3 | 财务数据 | `stocksystem/financial.js` | `StockFinancialController` | 5 | `/stocksystem/financial` |
| 4 | 指数行情 | `stocksystem/stockindex.js` | `StockIndexController` | 5 | `/stocksystem/stockindex` |
| 5 | 涨跌停板 | `stocksystem/stockslimit.js` | `StocksLimitController` | 5 | `/stocksystem/stockslimit` |
| 6 | 动量结果 | `stocksystem/trends.js` | `TrendsController` | 5 (+9 扩展) | `/stocksystem/trends` |
| 7 | 动量个股 | `stocksystem/trendStocks.js` | `StocksInTrendController` | 5 | `/stocksystem/trendStocks` |
| 8 | 创新高低 | `stocksystem/newrecord.js` | `StocksNewRecordController` | 5 (+2 扩展) | `/stocksystem/newrecord` |
| 9 | 股票记账 | `stocksystem/book.js` | `StocksBookController` | 5 | `/stocksystem/book` |
**股票系统模块小计:约 63 个接口**
#### 1.2.5 工具与通用模块
| 序号 | 模块 | 前端 API 文件 | 后端 Controller | 接口数 | 基础路径 |
|------|------|--------------|-----------------|--------|----------|
| 1 | 代码生成 | `tool/gen.js` | `GenController` | 9 | `/tool/gen` |
| 2 | 登录认证 | `login.js` | `SysLoginController` / `CaptchaController` | 6 | `/login`, `/register` 等 |
| 3 | 路由信息 | `menu.js` | `SysLoginController` | 1 | `/getRouters` |
| 4 | 首页聚合 | `index.js` | 多 Controller 组合 | 16 | 分散 |
| 5 | 通用上传 | - | `CommonController` | 2 | `/common/upload`, `/common/download` |
**工具与通用模块小计:约 34 个接口**
### 1.3 分类统计
| 模块大类 | 接口数量 | 占比 |
|----------|----------|------|
| 系统管理 | ~69 | 38% |
| 监控管理 | ~20 | 11% |
| 记账系统 | ~30 | 17% |
| 股票系统 | ~63 | 35% |
| 工具与通用 | ~34 | - |
| **合计** | **~182** | **100%** |
---
## 2. 请求/响应格式
### 2.1 统一响应格式
所有 API 接口统一使用 `AjaxResult` 作为响应载体,其本质是 `HashMap<String, Object>`
#### 2.1.1 成功响应(无数据)
```json
{
"code": 200,
"msg": "操作成功"
}
```
#### 2.1.2 成功响应(带数据)
```json
{
"code": 200,
"msg": "操作成功",
"data": {
"userId": 1,
"userName": "admin"
}
}
```
#### 2.1.3 成功响应(多字段 — AjaxResult.put 扩展)
```json
{
"code": 200,
"msg": "操作成功",
"data": { /* 用户详情 */ },
"roles": [ /* 角色列表 */ ],
"posts": [ /* 岗位列表 */ ],
"postIds": [1, 2],
"roleIds": [1]
}
```
> **注意**:后端使用 `ajax.put(key, value)` 动态追加字段,前端通过 `response.roles` 等方式访问。
#### 2.1.4 分页响应TableDataInfo
```json
{
"total": 100,
"rows": [
{ "userId": 1, "userName": "admin" },
{ "userId": 2, "userName": "test" }
],
"code": 200,
"msg": "查询成功"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `total` | `long` | 总记录数 |
| `rows` | `List<?>` | 当前页数据列表 |
| `code` | `int` | 状态码(固定 200 |
| `msg` | `String` | 消息文本 |
#### 2.1.5 失败响应
```json
{
"code": 500,
"msg": "新增用户'admin'失败,登录账号已存在"
}
```
### 2.2 请求格式规范
#### 2.2.1 查询列表GET
```javascript
// 前端
export function listUser(query) {
return request({ url: '/system/user/list', method: 'get', params: query })
}
// 请求参数通过 URL Query 传递
GET /system/user/list?pageNum=1&pageSize=10&userName=admin&status=0
```
#### 2.2.2 查询详情GET + PathVariable
```javascript
export function getUser(userId) {
return request({ url: '/system/user/' + userId, method: 'get' })
}
// 请求
GET /system/user/1
```
#### 2.2.3 新增POST + JSON Body
```javascript
export function addUser(data) {
return request({ url: '/system/user', method: 'post', data: data })
}
// 请求头: Content-Type: application/json;charset=utf-8
POST /system/user
Body: { "userName": "test", "phonenumber": "13800138000" }
```
#### 2.2.4 修改PUT + JSON Body
```javascript
export function updateUser(data) {
return request({ url: '/system/user', method: 'put', data: data })
}
PUT /system/user
Body: { "userId": 1, "userName": "admin" }
```
#### 2.2.5 删除DELETE + PathVariable
```javascript
export function delUser(userId) {
return request({ url: '/system/user/' + userId, method: 'delete' })
}
DELETE /system/user/1
```
> 后端实际接收 `Long[]` 数组,支持批量删除:`DELETE /system/user/1,2,3`
#### 2.2.6 文件下载POST + Blob
```javascript
export function download(url, params, filename) {
return service.post(url, params, {
transformRequest: [(params) => { return tansParams(params) }],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob'
})
}
```
#### 2.2.7 登录请求(跳过 Token
```javascript
export function login(username, password, code, uuid) {
return request({
url: '/login',
headers: { isToken: false }, // 不携带 Token
method: 'post',
data: { username, password, code, uuid }
})
}
```
### 2.3 登录认证机制
| 环节 | 说明 |
|------|------|
| Token 载体 | JWT Token |
| Token 传递 | `Authorization: Bearer {token}` |
| 请求头配置 | `axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'` |
| Token 跳过 | `headers: { isToken: false }` |
| 超时时间 | 60 秒(验证码接口 20 秒) |
---
## 3. 错误处理机制
### 3.1 前端响应拦截器
位置:`ruoyi-ui/src/utils/request.js`
```javascript
service.interceptors.response.use(res => {
const code = res.data.code || 200; // 默认成功
const msg = errorCode[code] || res.data.msg || errorCode['default']
// 二进制数据直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
// 弹出确认框 → 重新登录
MessageBox.confirm('登录状态已过期...', '系统提示', {...})
return Promise.reject('无效的会话...')
} else if (code === 500) {
// 全局 Message.error 提示
Message({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code !== 200) {
// 其他错误码 → Notification.error
Notification.error({ title: msg })
return Promise.reject('error')
} else {
return res.data // 正常返回
}
}, error => {
// HTTP 层错误处理
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
Message({ message, type: 'error', duration: 5000 })
return Promise.reject(error)
})
```
### 3.2 后端全局异常处理
位置:`ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java`
| 异常类型 | 处理方式 | 返回状态码 |
|----------|----------|------------|
| `AccessDeniedException` | 权限校验失败 | `403` — "没有权限,请联系管理员授权" |
| `HttpRequestMethodNotSupportedException` | 不支持的请求方法 | `500` — 异常消息 |
| `ServiceException` | 业务异常(带自定义 code | code 或 `500` |
| `BindException` | 参数校验失败 | `500` — 校验错误消息 |
| `MethodArgumentNotValidException` | @Valid 校验失败 | `500` — 字段错误消息 |
| `DemoModeException` | 演示模式限制 | `500` — "演示模式,不允许操作" |
| `RuntimeException` | 未知运行时异常 | `500` — 异常消息 |
| `Exception` | 兜底系统异常 | `500` — 异常消息 |
### 3.3 错误码体系
位置:`ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java`
| 状态码 | 常量名 | 含义 |
|--------|--------|------|
| 200 | `SUCCESS` | 操作成功 |
| 201 | `CREATED` | 对象创建成功 |
| 202 | `ACCEPTED` | 请求已被接受 |
| 204 | `NO_CONTENT` | 操作成功但无返回数据 |
| 301 | `MOVED_PERM` | 资源已永久移除 |
| 303 | `SEE_OTHER` | 重定向 |
| 304 | `NOT_MODIFIED` | 资源未修改 |
| 400 | `BAD_REQUEST` | 参数错误 |
| 401 | `UNAUTHORIZED` | 未授权 / Token 过期 |
| 403 | `FORBIDDEN` | 访问受限 / 权限不足 |
| 404 | `NOT_FOUND` | 资源/服务未找到 |
| 405 | `BAD_METHOD` | 不支持的 HTTP 方法 |
| 409 | `CONFLICT` | 资源冲突/被锁 |
| 415 | `UNSUPPORTED_TYPE` | 不支持的媒体类型 |
| 500 | `ERROR` | 系统内部错误 |
| 501 | `NOT_IMPLEMENTED` | 接口未实现 |
#### 前端错误码映射
位置:`ruoyi-ui/src/utils/errorCode.js`
```javascript
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
}
```
> **注意**:前端仅映射了 3 个业务错误码其余错误码400、409、415 等)直接 fallback 到后端返回的 `msg` 或 `default`。
### 3.4 错误处理流程图
```
HTTP 层错误 业务层错误
│ │
▼ ▼
Network Error / Timeout res.data.code
│ │
▼ ▼
Message.error code === 401 → MessageBox.confirm → 跳转登录
code === 500 → Message.error
code !== 200 → Notification.error
code === 200 → 正常返回 res.data
```
---
## 4. 分页 / 排序 / 过滤
### 4.1 分页实现
基于 **PageHelper** 实现,采用 ThreadLocal 模式。
#### 4.1.1 后端处理流程
```
前端请求 后端处理
│ │
│ GET /system/user/list │
│ ?pageNum=1&pageSize=10 │
▼ ▼
TableSupport.buildPageRequest()
PageUtils.startPage()
PageHelper.startPage(pageNum, pageSize, orderBy)
执行 MyBatis 查询(自动添加 LIMIT
BaseController.getDataTable(list)
new PageInfo(list).getTotal() → total
return TableDataInfo { total, rows, code, msg }
```
#### 4.1.2 分页参数
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|--------|------|------|--------|------|
| `pageNum` | `Integer` | 否 | - | 当前页码(从 1 开始) |
| `pageSize` | `Integer` | 否 | - | 每页记录数 |
| `orderByColumn` | `String` | 否 | - | 排序字段名 |
| `isAsc` | `String` | 否 | - | 排序方向:`asc` 或 `desc`,多字段用逗号分隔 |
| `reasonable` | `Boolean` | 否 | - | 分页合理化pageNum<=0 查第一页pageNum>总页数查最后一页) |
#### 4.1.3 后端代码示例
```java
@GetMapping("/list")
public TableDataInfo list(SysUser user) {
startPage(); // 从请求参数读取分页信息
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list); // 封装为 TableDataInfo
}
```
### 4.2 排序规范
#### 4.2.1 排序参数传递
```javascript
// 前端通过分页组件传递
{
pageNum: 1,
pageSize: 10,
orderByColumn: 'createTime',
isAsc: 'desc'
}
```
#### 4.2.2 多字段排序
```
isAsc: createTime desc,updateTime desc
```
#### 4.2.3 SQL 注入防护
```java
// SqlUtil.escapeOrderBySql() 方法对排序字段进行转义
// 只允许字母、数字、下划线、点号、逗号、空格、ASC、DESC
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
PageHelper.orderBy(orderBy);
```
### 4.3 过滤规范
#### 4.3.1 列表查询过滤
采用 **对象参数绑定** 方式:
```java
// 后端
@GetMapping("/list")
public TableDataInfo list(SysUser user) {
startPage();
// user 对象自动绑定 query 参数中的字段
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}
// 前端
GET /system/user/list?userName=admin&phonenumber=138&status=0
```
#### 4.3.2 权限过滤
```java
// 每个接口通过 @PreAuthorize 进行权限校验
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user) { ... }
```
#### 4.3.3 数据权限过滤
```java
// 在 Service 层通过 AOP 实现数据权限(部门数据范围)
// 支持:全部数据、本部门数据、本部门及以下、仅本人数据、自定义数据范围
```
### 4.4 导出/导入规范
| 操作 | HTTP 方法 | 路径模式 | 说明 |
|------|-----------|----------|------|
| 导出 Excel | `POST` | `/{module}/export` | 直接写入 HttpServletResponse |
| 导入 Excel | `POST` | `/{module}/importData` | MultipartFile + updateSupport 参数 |
| 下载模板 | `POST` | `/{module}/importTemplate` | 返回空模板文件 |
---
## 5. 存在的问题
### 5.1 问题清单
| # | 问题类型 | 严重程度 | 问题描述 | 涉及范围 | 优化建议 |
|---|----------|----------|----------|----------|----------|
| 1 | **响应格式不统一** | 高 | `AjaxResult`(普通 CRUD`TableDataInfo`(分页列表)返回结构完全不同:前者用 `data` 字段,后者用 `rows` + `total` 字段。前端需要分别处理两种响应结构,增加认知负担。 | 全部列表接口 vs 详情/操作接口 | 统一使用单一响应结构,如 `{ code, msg, data: { list, total } }`,或在 TableDataInfo 中也使用 `data` 字段包裹 |
| 2 | **错误码体系不完整** | 中 | 前端 `errorCode.js` 仅映射了 401/403/404 三个错误码400/409/415 等 HTTP 标准错误码未做前端映射,全部 fallback 到 `default` 或后端 `msg`。后端虽定义了 16 个状态码,但实际使用集中在 200 和 500。 | 全局错误处理 | 完善前端错误码映射表;后端减少 500 的滥用,对参数错误返回 400对业务冲突返回 409 |
| 3 | **排序字段 SQL 注入风险** | 高 | 虽然使用了 `SqlUtil.escapeOrderBySql()` 进行过滤,但正则表达式级别的过滤存在被绕过的可能。排序参数直接从请求参数读取并拼接到 SQL ORDER BY 子句中。 | `TableSupport` + `SqlUtil` | 使用白名单机制,仅允许传入已知的字段名;或使用 MyBatis 动态 SQL 的 `<choose>` 标签做安全排序 |
| 4 | **前后端 API 路径不一致** | 中 | 前端 `index.js` 调用 `/stocksystem/stocks/groupLimitlist`,而后端 `StocksController` 中该方法被注释了权限控制(`@PreAuthorize` 被注释)。另外部分接口前端使用 `/querylist`,后端映射为 `/list`,存在冗余接口。 | 股票系统模块 | 清理未使用的接口;补全权限控制;统一前后端路径命名规范 |
| 5 | **分页参数隐式依赖** | 中 | 分页参数通过 `ServletUtils.getParameter()` 从 HttpServletRequest 中隐式读取,而非通过 `@RequestParam` 显式声明。这使得 API 文档(如 Swagger无法自动生成分页参数说明API 可读性差。 | `TableSupport.getPageDomain()` | 使用 `@RequestParam(defaultValue = "1") Integer pageNum` 显式声明分页参数,或使用 `PageRequest` 对象作为 Controller 方法参数 |
| 6 | **HTTP 状态码与业务状态码混用** | 中 | 后端 HTTP Response 的 Status Code 始终为 200真正的业务状态码在响应体 `code` 字段中。这导致前端无法利用 HTTP 状态码进行路由/拦截逻辑,也与 RESTful 最佳实践不符。 | 全局 | 保持当前模式(业界常见做法)但需在文档中明确说明;或改为 HTTP Status Code 与业务 code 一致 |
| 7 | **GET 请求参数转换方式不标准** | 低 | 前端 GET 请求的 `params` 被手动拼接为 URL 字符串(`tansParams` 函数),而不是使用 axios 原生的 `paramsSerializer`。这可能导致特殊字符编码问题。 | `request.js` 请求拦截器 | 使用 axios 的 `paramsSerializer` 配置,或 `URLSearchParams` 进行参数序列化 |
| 8 | **批量删除路径参数格式不一致** | 低 | 部分 Controller 使用 `@DeleteMapping("/{ids}")` 接收 `Long[]`,但 URL 中数组的传递格式(逗号分隔 vs 多次参数)缺乏统一规范,前端需要手动拼接字符串。 | 所有支持批量删除的接口 | 统一使用 `@DeleteMapping` + `@RequestParam List<Long> ids``@RequestBody` 传递数组 |
| 9 | **大量调试代码未清理** | 低 | `StocksController` 中存在大量 `System.out.println()` 调试输出(超过 50 处以及大段被注释的代码1000+ 行)。这些代码在生产环境中会污染日志,且增加维护成本。 | `stock-system` 模块 | 统一替换为 `logger.info/debug`;清理历史注释代码 |
| 10 | **接口文档缺失** | 中 | 项目虽引入了 Swagger 依赖(`TestController` 中有示例),但所有业务 Controller 均未添加 Swagger 注解(`@Api`、`@ApiOperation`、`@ApiParam` 等),导致无法自动生成 API 文档。 | 全部 Controller | 补充 Swagger/OpenAPI 注解;或接入 SpringDoc / Knife4j |
### 5.2 综合优化建议
#### 短期优化1-2 周)
1. **补充前端错误码映射**:在 `errorCode.js` 中补充 400/409/415 等常见错误码的中文提示
2. **清理调试代码**:将 `StocksController` 中的 `System.out.println` 替换为 `logger`
3. **补全权限注解**:取消 `StocksController` 中被注释的 `@PreAuthorize`
#### 中期优化1-2 月)
4. **接入 API 文档**:为所有 Controller 补充 Swagger 注解,启用 Knife4j 文档页面
5. **规范分页参数**:考虑使用 `@Validated` 显式声明分页参数
6. **统一响应格式**:评估是否需要统一 `AjaxResult``TableDataInfo` 的字段结构
#### 长期优化(持续)
7. **排序安全加固**:实施白名单机制替代正则过滤
8. **RESTful 对齐**:评估是否将业务状态码与 HTTP 状态码对齐
9. **API 版本管理**:当接口变更时引入 `/api/v1/` 等版本前缀
---
## 附录
### A. 关键技术栈
| 层级 | 技术 | 版本 |
|------|------|------|
| 前端框架 | Vue 2 + Element UI | 2.x |
| HTTP 客户端 | Axios | - |
| 后端框架 | Spring Boot | 2.x |
| Web 框架 | Spring MVC | - |
| 权限框架 | Spring Security | - |
| 分页组件 | PageHelper | - |
| ORM | MyBatis | - |
### B. 核心文件路径
| 文件 | 路径 |
|------|------|
| 前端请求封装 | `ruoyi-ui/src/utils/request.js` |
| 前端错误码映射 | `ruoyi-ui/src/utils/errorCode.js` |
| 前端 API 目录 | `ruoyi-ui/src/api/` |
| 后端统一响应 | `ruoyi-common/.../AjaxResult.java` |
| 后端分页响应 | `ruoyi-common/.../TableDataInfo.java` |
| 后端分页工具 | `ruoyi-common/.../PageUtils.java` |
| 后端排序支持 | `ruoyi-common/.../TableSupport.java` |
| 后端全局异常 | `ruoyi-framework/.../GlobalExceptionHandler.java` |
| 后端状态码常量 | `ruoyi-common/.../HttpStatus.java` |
| 后端 BaseController | `ruoyi-common/.../BaseController.java` |
### C. HTTP 方法使用统计
| 方法 | 用途 | 使用频率 |
|------|------|----------|
| `GET` | 查询列表、查询详情、查询树结构、下载 | ~45% |
| `POST` | 新增、登录、注册、导出、导入、分析 | ~30% |
| `PUT` | 修改、状态变更、授权、重置密码 | ~20% |
| `DELETE` | 删除、清空日志、刷新缓存 | ~5% |