> 后端项目:`zero-pro`(Spring Boot 3 + Spring Security + MyBatis-Plus)
> 服务器端口(dev):`8848` | 上下文路径:无
> 本文档由代码扫描整理,覆盖 `controller` 包下全部 HTTP 接口(92 个)与 WebSocket 接口(1 个)。
## 通用说明
### 认证方式
所有受保护接口需在请求头携带 Token:
```
Authorization: Bearer <token>
```
Token 通过 `POST /login` 获取。未登录访问受保护接口返回 401。
### 统一响应结构 `ResponseResult<T>`
```json
{
"code": "200",
"msg": "成功",
"data": {}
}
```
| 字段 | 类型 | 说明 |
| ---- | ---- | ---- |
| code | string | 状态码,`200` 成功 |
| msg | string | 提示信息 |
| data | T | 业务数据(`null` 字段不序列化) |
### 分页查询通用参数 `BaseQueryPage`
所有 `getList` 类接口的请求体均继承以下字段:
| 字段 | 类型 | 说明 |
| ---- | ---- | ---- |
| current | int | 当前页(从 1 开始) |
| size | int | 每页条数 |
| searchTitle | string | 通用搜索关键字 |
| status | string | 状态筛选 |
分页返回(MyBatis-Plus `IPage`):
```json
{
"code": "200",
"msg": "成功",
"data": {
"records": [],
"total": 0,
"size": 10,
"current": 1,
"pages": 0
}
}
```
### 权限标识
接口上的 `@PreAuthorize("@psp.hasPermission('xxx')")` 为权限标识,用户需拥有对应权限才能访问。
---
## 1. 登录模块(LoginController)
### 1.1 登录
- **请求方式**:`POST /login`
- **请求体** `LoginBody`:
| 字段 | 类型 | 必填 | 说明 |
| ---- | ---- | ---- | ---- |
| username | string | 是 | 用户名 |
| password | string | 是 | 密码 |
| code | string | 否 | 验证码 |
- **返回 `data`**:
```json
{ "token": "eyJhbGciOiJIUzI1NiJ9..." }
```
### 1.2 注册用户
- **请求方式**:`POST /register`
- **请求体** `UserBo`:`username`(必填,校验格式)、`password`(必填,校验格式)、`email`
### 1.3 发送验证码
- **请求方式**:`POST /sendCode`
- **Query 参数**:`email`(string,必填)
- **说明**:向指定邮箱发送注册验证码
---
## 2. 用户模块(UserController)
### 2.1 获取当前用户信息
- **请求方式**:`GET /system/getUserInfo`
- **返回 `data`**:`CacheUserInfo`
| 字段 | 类型 | 说明 |
| ---- | ---- | ---- |
| userId | int | 用户ID |
| loginTime | long | 登录时间戳 |
| expireTime | long | 过期时间戳 |
| user | User | 用户实体(不含密码) |
| deptId | long | 部门ID |
| role | Role | 角色 |
| username | string | 用户名 |
### 2.2 修改用户信息
- **请求方式**:`PUT /system/updateUserinfo`|权限:`sys:user:update`
- **请求体** `UserInfoBo`:`userId`、`nickName`、`email`、`sex`、`avatar`、`enabled`
### 2.3 获取用户列表
- **请求方式**:`POST /system/users/get`|权限:`sys:user:list`
- **请求体** `UserDto`(继承 BaseQueryPage):`username`、`nickName`
- **返回 `data`**:`IPage<UserVo>`(见下方分页结构)
`UserVo` 字段:`userId`、`username`、`nickName`、`email`、`sex`、`avatar`、`enabled`、`createTime`、`updateTime`、`delFlag`、`roleId`、`roleName`、`roleKey`、`status`
### 2.4 新增用户
- **请求方式**:`POST /system/user/save`|权限:`sys:user:save`
- **请求体** `UserBo`:`username`、`password`、`email`
### 2.5 删除用户
- **请求方式**:`DELETE /system/user/delete/{id}`|权限:`sys:user:delete`
- **路径参数**:`id`(int,用户ID)
### 2.6 分配用户角色
- **请求方式**:`PUT /system/user/assignRole`|权限:`sys:user:role`
- **Query 参数**:`userId`(int,必填)、`roleId`(int,必填)
### 2.7 重置用户初始密码
- **请求方式**:`DELETE /system/user/password/{id}`|权限:`sys:user:password:init`
- **路径参数**:`id`(int,用户ID)
### 2.8 修改密码
- **请求方式**:`PUT /system/user/password/update/{id}`|权限:`sys:user:password:update`
- **路径参数**:`id`(int,用户ID)
- **请求体** `UserPasswordBo`:`username`、`password`(原密码)、`newPassword`(新密码)
---
## 3. 角色模块(RoleController)
### 3.1 查询角色
- **请求方式**:`GET /roles/get`|权限:`sys:role:list`
- **Query 参数**:`status`(string,必填)|`2` 禁用,`1` 启用,`3` 全部
- **返回 `data`**:`List<RoleVo>`(`roleId`、`roleName`、`roleKey`)
### 3.2 增加角色
- **请求方式**:`POST /role/add`|权限:`sys:role:add`
- **请求体** `RoleBo`:`roleName`、`roleKey`(默认 `Guest`)
### 3.3 修改角色
- **请求方式**:`PUT /role/update`|权限:`sys:role:update`
- **请求体** `RoleDto`:`roleId`(int)、`roleName`、`roleKey`、`status`
### 3.4 删除角色
- **请求方式**:`DELETE /role/delete/{id}`(无权限注解)
- **路径参数**:`id`(int)
### 3.5 为角色增加菜单或按钮权限
- **请求方式**:`POST /role/rolePermission/add`|权限:`sys:role:permission:add`
- **请求体** `RolePerBo`:
| 字段 | 类型 | 必填 | 说明 |
| ---- | ---- | ---- | ---- |
| roleId | int | 是 | 角色ID |
| menuIds | int[] | 是 | 菜单ID数组 |
### 3.6 查询角色下的菜单或按钮
- **请求方式**:`GET /role/menuPermission/get/{roleId}`|权限:`sys:role:permission:list`
- **路径参数**:`roleId`(int)
- **返回 `data`**:`List<RoleMenuVo>`(继承 `MenuVo`,含 `roleId` 字段,树形)
### 3.7 查询角色的叶子菜单ID(回显选中)
- **请求方式**:`GET /role/menuPermission/leafIds/{roleId}`|权限:`sys:role:permission:list`
- **返回 `data`**:`List<Integer>` 叶子菜单ID数组
### 3.8 查询所有默认菜单或按钮
- **请求方式**:`GET /role/menuPermission/all`|权限:`sys:role:permission:list`
- **返回 `data`**:`List<MenuVo>`(树形)
---
## 4. 菜单模块(MenuController)
### 4.1 菜单列表(分页)
- **请求方式**:`POST /menus/list`|权限:`sys:menu:list`
- **请求体** `MenuBo`(继承 BaseQueryPage):`menuId`(string);其余搜索字段:菜单名、路由地址、组件、权限标识
- **返回 `data`**:分页数据
### 4.2 获取当前账号菜单
- **请求方式**:`GET /menu/get`
- **返回 `data`**:`List<MenuVo>`(树形)
`MenuVo` 字段:`menuId`、`menuName`、`parentId`、`path`、`component`、`cache`、`perms`、`menuType`、`orderNum`、`createTime`、`updateTime`、`remark`、`status`、`mobileLayout`、`icon`、`children`
### 4.3 新增菜单
- **请求方式**:`POST /menu/save`
- **请求体** `Menu` 实体:`menuId`、`menuName`、`parentId`、`path`、`component`、`cache`、`perms`、`menuType`、`orderNum`、`remark`、`status`、`mobileLayout`、`icon`
### 4.4 删除菜单
- **请求方式**:`GET /menu/delete/{id}`(注意:使用 GET 而非 DELETE)
- **路径参数**:`id`(string,菜单ID)
---
## 5. 文件模块(UploadFileController)
### 5.1 文件上传
- **请求方式**:`POST /file/upload/{type}`
- **路径参数**:`type`(int)|`1` 本地存储,`2` 对象存储(OSS)
- **请求参数**:`multipart/form-data`,字段名 `file`
- **返回 `data`**:本地存储返回 `null`;对象存储返回文件 URL 字符串
---
## 6. 系统设置(SysSmtpController)
### 6.1 保存邮件配置
- **请求方式**:`POST /settings/saveSysSmtp`|权限:`sys:seting:smtp:save`
- **请求体** `SysSmtpConfig`:`smtpHostname`、`smtpUsername`、`smtpKey`、`nickName`、`port`、`encrypt`、`isOpen`
### 6.2 发送验证码
- **请求方式**:`POST /settings/sendCodeBy/{username}`
- **路径参数**:`username`(string)
### 6.3 生成分布式ID
- **请求方式**:`GET /settings/getId`
- **Query 参数**:`bizKey`(string)
- **返回 `data`**:int(Leaf 发号器生成的自增ID)
---
## 7. 地图发卡器模块(MapBoxAccountController)
### 7.1 获取信用卡列表
- **请求方式**:`POST /mapbox/getCreditCards`
- **请求体** `BaseQueryPage`
- **返回 `data`**:分页数据,元素为 `CreditCard`(`id`、`type`、`cardNumber`、`expired`、`cvc`、`city`、`state`、`fullState`、`postcode`、`uid`)
### 7.2 新增信用卡
- **请求方式**:`POST /mapbox/insertCreditCard`
- **请求体** `CreditCard` 实体
### 7.3 删除信用卡
- **请求方式**:`GET /mapbox/deleteCreditCard/{id}`(注意:使用 GET)
- **路径参数**:`id`(int)
### 7.4 获取账户列表
- **请求方式**:`POST /mapbox/getMapboxAccount`
- **请求体** `BaseQueryPage`
- **返回 `data`**:分页数据,元素为 `ProtonMail`(`id`、`send`、`username`、`email`、`password`、`mapAccount`、`mapPassword`、`mapPublicKey`)
### 7.5 新增账户
- **请求方式**:`POST /mapbox/insertMapboxAccount`
- **请求体** `ProtonMail` 实体
### 7.6 删除账户
- **请求方式**:`GET /mapbox/deleteMapboxAccount/{id}`(注意:使用 GET)
- **路径参数**:`id`(int)
---
## 8. 消息发送模块(SendMsgController)
### 8.1 发送消息
- **请求方式**:`POST /zero/sendMsg`
- **请求体**:原始字符串 `String`(推送消息内容)
---
## 9. Bark 设备与任务管理(SysBarkController)
### 9.1 查询所有 bark 配置
- **请求方式**:`GET /bark/config/getAll`|权限:`sys:bark:list`
- **返回 `data`**:`List<SysBarkConfig>`(`id`、`title`、`subtitle`、`body`、`deviceKey`、`level`、`volume`、`badge`、`call`、`sound`、`icon`、`group`、`url`、`isArchive`、`action`)
### 9.2 分页查询 bark 设备
- **请求方式**:`POST /bark/device/getList`|权限:`sys:bark:list`
- **请求体** `SysBarkDeviceDto`(继承 BaseQueryPage):`device`、`username`、`serverUrl`
- **返回 `data`**:分页数据,元素为 `SysBarkDeviceVo`(`id`、`serverUrl`、`serverKey`、`username`、`device`、`isEnable`)
### 9.3 查询所有 bark 设备
- **请求方式**:`GET /bark/device/getAll`|权限:`sys:bark:list`
- **返回 `data`**:`List<SysBarkDeviceVo>`
### 9.4 新增 bark 设备
- **请求方式**:`POST /bark/device/save`|权限:`sys:bark:add`
- **请求体** `SysBarkDeviceBo`:`id`(修改时必填)、`serverUrl`(必填)、`serverKey`(必填)、`username`(必填)、`device`(必填)、`isEnable`
### 9.5 修改 bark 设备
- **请求方式**:`PUT /bark/device/update`|权限:`sys:bark:update`
- **请求体** `SysBarkDeviceBo`
### 9.6 删除 bark 设备
- **请求方式**:`DELETE /bark/device/delete/{id}`|权限:`sys:bark:delete`
- **路径参数**:`id`(int)
### 9.7 分页查询 bark 任务
- **请求方式**:`POST /bark/task/getList`|权限:`sys:bark:task:list`
- **请求体** `SysBarkTaskDto`(继承 BaseQueryPage):`title`、`device`、`username`、`isSingle`
- **返回 `data`**:分页数据,元素为 `SysBarkTaskListVo`(`id`、`configId`、`title`、`deviceId`、`device`、`username`、`isSingle`、`nextSend`、`dayCycleSend`、`hourCycleSend`、`hourCycleSendStart`、`hourCycleSendEnd`)
### 9.8 根据设备ID查询任务列表
- **请求方式**:`GET /bark/task/getByDevice/{deviceId}`|权限:`sys:bark:task:list`
- **路径参数**:`deviceId`(int)
- **返回 `data`**:`List<SysBarkTaskVo>`(继承 `SysBarkConfig`,含任务字段)
### 9.9 新增 bark 任务
- **请求方式**:`POST /bark/task/save`|权限:`sys:bark:task:add`
- **请求体** `SysBarkTaskBo`:
| 字段 | 类型 | 必填 | 说明 |
| ---- | ---- | ---- | ---- |
| id | int | 是 | ID |
| configId | int | 是 | 配置ID |
| deviceId | int | 是 | 设备ID |
| isSingle | string | 是 | 发送类型:1单次,2每日循环,3单日循环 |
| nextSend | datetime | 否 | 下次发送时间 |
| dayCycleSend | time | 否 | 每日循环时间 |
| hourCycleSend | time | 否 | 单日循环周期 |
| hourCycleSendStart | time | 否 | 单日循环开始 |
| hourCycleSendEnd | time | 否 | 单日循环结束 |
### 9.10 修改 bark 任务
- **请求方式**:`PUT /bark/task/update`|权限:`sys:bark:task:update`
- **请求体** `SysBarkTaskBo`
### 9.11 删除 bark 任务(按配置ID)
- **请求方式**:`DELETE /bark/task/deleteByConfig/{configId}`|权限:`sys:bark:task:delete`
- **路径参数**:`configId`(int)
### 9.12 删除 bark 任务(按配置ID+设备ID)
- **请求方式**:`DELETE /bark/task/delete/{configId}/{deviceId}`|权限:`sys:bark:task:delete`
- **路径参数**:`configId`(int)、`deviceId`(int)
---
## 10. 定时任务模块(QuartzController,前缀 `/quartz`)
### 10.1 创建定时任务(默认启动)
- **请求方式**:`POST /quartz/config/add`
- **请求体** `QuartzBean`:`id`、`jobName`、`jobClass`、`status`、`cronExpression`
### 10.2 修改定时任务
- **请求方式**:`PUT /quartz/config/edit`
- **请求体** `QuartzBean`
### 10.3 首次启动任务
- **请求方式**:`GET /quartz/config/enable/{id}/{jobName}`
- **路径参数**:`id`(int)、`jobName`(string)
### 10.4 删除定时任务
- **请求方式**:`GET /quartz/config/delete/{id}/{jobName}`
### 10.5 恢复定时任务
- **请求方式**:`GET /quartz/config/resume/{id}/{jobName}`
### 10.6 暂停定时任务
- **请求方式**:`PUT /quartz/config/pause/{id}/{jobName}`
### 10.7 立即执行一次任务
- **请求方式**:`PUT /quartz/config/run/{id}/{jobName}`
### 10.8 获取定时任务(分页)
- **请求方式**:`POST /quartz/config/list`
- **请求体** `BaseQueryPage`
- **返回 `data`**:`IPage<QuartzBean>`
---
## 11. 测试模块(TestController)
### 11.1 测试接口
- **请求方式**:`POST /testPost`
- **请求体** `User` 实体(回显返回)
---
## 12. 游戏服务器模块(RemoteServerStatusController,前缀 `/remoteServer`)
### 12.1 查询游戏服务器状态
- **请求方式**:`GET /remoteServer/status/{game}`
- **路径参数**:`game`(string,游戏标识,如 `PUBG`)
- **返回 `data`**:第三方 API(`api.pubg.plus/Server`)返回的 JSON 对象
---
## 13. 食品保质期管理(FoodController)
### 13.1 食品分类
#### 13.1.1 分页查询食品分类列表
- **请求方式**:`POST /food/category/getList`|权限:`food:category:list`
- **请求体** `FoodCategoryDto`(继承 BaseQueryPage):`name`
- **返回 `data`**:分页数据,元素为 `FoodCategoryVo`(`id`、`name`、`icon`、`sortOrder`、`createTime`)
#### 13.1.2 查询所有食品分类
- **请求方式**:`GET /food/category/getAll`|权限:`food:category:list`
- **返回 `data`**:`List<FoodCategoryVo>`
#### 13.1.3 新增食品分类
- **请求方式**:`POST /food/category/save`|权限:`food:category:add`
- **请求体** `FoodCategoryBo`:`id`(修改时必填)、`name`(必填)、`icon`、`sortOrder`
#### 13.1.4 修改食品分类
- **请求方式**:`PUT /food/category/update`|权限:`food:category:update`
- **请求体** `FoodCategoryBo`
#### 13.1.5 删除食品分类
- **请求方式**:`DELETE /food/category/delete/{id}`|权限:`food:category:delete`
- **路径参数**:`id`(long)
### 13.2 存储位置
#### 13.2.1 分页查询存储位置列表
- **请求方式**:`POST /food/location/getList`|权限:`food:location:list`
- **请求体** `FoodLocationDto`(继承 BaseQueryPage):`name`
- **返回 `data`**:分页数据,元素为 `FoodLocationVo`(`id`、`name`、`icon`、`sortOrder`、`createTime`)
#### 13.2.2 查询所有存储位置
- **请求方式**:`GET /food/location/getAll`|权限:`food:location:list`
- **返回 `data`**:`List<FoodLocationVo>`
#### 13.2.3 新增存储位置
- **请求方式**:`POST /food/location/save`|权限:`food:location:add`
- **请求体** `FoodLocationBo`:`id`(修改时必填)、`name`(必填)、`icon`、`sortOrder`
#### 13.2.4 修改存储位置
- **请求方式**:`PUT /food/location/update`|权限:`food:location:update`
- **请求体** `FoodLocationBo`
#### 13.2.5 删除存储位置
- **请求方式**:`DELETE /food/location/delete/{id}`|权限:`food:location:delete`
- **路径参数**:`id`(long)
### 13.3 条形码商品库
#### 13.3.1 分页查询条形码商品列表
- **请求方式**:`POST /food/barcode/getList`|权限:`food:barcode:list`
- **请求体** `FoodBarcodeDto`(继承 BaseQueryPage):`barcode`、`name`、`brand`
- **返回 `data`**:分页数据,元素为 `FoodBarcodeVo`(`id`、`barcode`、`name`、`brand`、`categoryId`、`categoryName`、`shelfLifeDays`、`imageUrl`、`createTime`)
#### 13.3.2 根据条形码查询商品
- **请求方式**:`GET /food/barcode/getByCode/{barcode}`|权限:`food:barcode:list`
- **路径参数**:`barcode`(string)
- **返回 `data`**:`FoodBarcodeVo`
#### 13.3.3 新增条形码商品
- **请求方式**:`POST /food/barcode/save`|权限:`food:barcode:add`
- **请求体** `FoodBarcodeBo`:`id`(修改时必填)、`barcode`(必填)、`name`(必填)、`brand`、`categoryId`、`shelfLifeDays`、`imageUrl`
#### 13.3.4 修改条形码商品
- **请求方式**:`PUT /food/barcode/update`|权限:`food:barcode:update`
- **请求体** `FoodBarcodeBo`
#### 13.3.5 删除条形码商品
- **请求方式**:`DELETE /food/barcode/delete/{id}`|权限:`food:barcode:delete`
- **路径参数**:`id`(long)
### 13.4 食品库存
#### 13.4.1 分页查询食品库存列表
- **请求方式**:`POST /food/item/getList`|权限:`food:list`
- **请求体** `FoodItemDto`(继承 BaseQueryPage):`name`、`categoryId`、`locationId`、`foodStatus`(1正常 2即将过期 3紧急过期 4已过期)、`barcode`
- **返回 `data`**:分页数据,元素为 `FoodItemVo`
`FoodItemVo` 字段:`id`、`categoryId`、`categoryName`、`categoryIcon`、`locationId`、`locationName`、`locationIcon`、`name`、`brand`、`barcode`、`productionDate`、`expiryDate`、`shelfLifeDays`、`remainingDays`、`quantity`、`unit`、`imageUrl`、`remark`、`status`、`createTime`
#### 13.4.2 查询食品详情
- **请求方式**:`GET /food/item/getById/{id}`|权限:`food:list`
- **路径参数**:`id`(long)
- **返回 `data`**:`FoodItemVo`
#### 13.4.3 新增食品
- **请求方式**:`POST /food/item/save`|权限:`food:add`
- **请求体** `FoodItemBo`:
| 字段 | 类型 | 必填 | 说明 |
| ---- | ---- | ---- | ---- |
| id | long | 修改时 | 食品ID |
| categoryId | long | 否 | 分类ID |
| locationId | long | 否 | 存储位置ID |
| name | string | 是 | 食品名称 |
| brand | string | 否 | 品牌 |
| barcode | string | 否 | 条形码 |
| productionDate | date | 否 | 生产日期 yyyy-MM-dd |
| expiryDate | date | 是 | 保质期到期日 yyyy-MM-dd |
| shelfLifeDays | int | 否 | 保质期天数 |
| quantity | int | 否 | 数量 |
| unit | string | 否 | 单位 |
| imageUrl | string | 否 | 图片URL |
| remark | string | 否 | 备注 |
#### 13.4.4 修改食品
- **请求方式**:`PUT /food/item/update`|权限:`food:update`
- **请求体** `FoodItemBo`
#### 13.4.5 删除食品
- **请求方式**:`DELETE /food/item/delete/{id}`|权限:`food:delete`
- **路径参数**:`id`(long)
#### 13.4.6 查询即将过期的食品
- **请求方式**:`GET /food/item/expiring/{days}`|权限:`food:list`
- **路径参数**:`days`(int,天数阈值,如 30)
- **返回 `data`**:`List<FoodItemVo>`
#### 13.4.7 查询已过期的食品
- **请求方式**:`GET /food/item/expired`|权限:`food:list`
- **返回 `data`**:`List<FoodItemVo>`
### 13.5 过期提醒
#### 13.5.1 分页查询过期提醒列表
- **请求方式**:`POST /food/alert/getList`|权限:`food:alert:list`
- **请求体** `FoodAlertDto`(继承 BaseQueryPage):`alertType`(1-30天内 2-7天内 3-已过期)、`notified`(0未通知 1已通知)
- **返回 `data`**:分页数据,元素为 `FoodAlertVo`(`id`、`foodItemId`、`foodName`、`alertType`、`alertDays`、`notified`、`notifyTime`、`createTime`)
#### 13.5.2 标记提醒为已通知
- **请求方式**:`PUT /food/alert/markNotified/{id}`|权限:`food:alert:update`
- **路径参数**:`id`(long)
#### 13.5.3 手动触发检查过期提醒
- **请求方式**:`POST /food/alert/check`|权限:`food:alert:add`
---
## 14. OCR 文字识别(FoodOcrController)
### 14.1 OCR 识别图片文字
- **请求方式**:`POST /food/ocr/recognize`
- **请求参数**:`multipart/form-data`,字段名 `file`(图片文件)
- **说明**:内部调用 OCR.space API(`api.ocr.space/parse/image`),自动提取识别文本中的日期
- **返回 `data`**:
```json
{
"text": "识别出的文本内容",
"dates": "2024-01-15,2026-12-31"
}
```
---
## 15. 条形码识别(BarcodeScanController)
### 15.1 识别图片中的条形码并查询商品信息
- **请求方式**:`POST /food/barcode/scan`
- **请求参数**:`multipart/form-data`,字段名 `file`(含条形码的图片)
- **说明**:ZXing 多重策略识别(原图/灰度/放大/二值化/全格式),成功后先查本地历史记录,再查第三方 API(OpenFoodFacts)
- **返回 `data`**:
| 字段 | 类型 | 说明 |
| ---- | ---- | ---- |
| barcode | string | 条形码 |
| format | string | 条形码格式(EAN_13、QR_CODE 等;摄像头查询为 CAMERA) |
| found | boolean | 是否找到商品信息 |
| fromHistory | boolean | 是否命中本地历史记录 |
| name | string | 商品名称 |
| brand | string | 品牌 |
| categoryId | long | 分类ID |
| categoryName | string | 分类名称 |
| locationId | long | 存储位置ID |
| locationName | string | 存储位置名称 |
| shelfLifeDays | int | 保质期天数 |
| imageUrl | string | 商品图片 |
### 15.2 根据条形码查询商品信息(摄像头扫码后调用)
- **请求方式**:`POST /food/barcode/lookup`
- **Query 参数**:`barcode`(string)
- **返回 `data`**:与 15.1 相同结构
---
## 16. 监控模块(WebSocket + HTTP)
### 16.1 WebSocket 服务端
- **地址**:`ws://<host>:5000/ws`(Undertow 独立端口 5000)
- **说明**:Agent 设备与 Web 端均通过该连接通信。
**Web 端订阅消息**:
```json
{ "type": "subscribe", "deviceId": "xxx" }
```
**Agent 设备上报消息**:含 `DeviceId` 字段的 JSON 监控数据,服务端实时转发给订阅该设备的 Web 端,并异步入库。
### 16.2 查询在线 Agent 设备
- **请求方式**:`POST /monitor/query`
- **返回 `data`**:
```json
{
"clientAgent": [{ "deviceId": "xxx", "online": 1 }],
"clientWeb": [{ "deviceId": "xxx", "online": 2 }],
"online": 10
}
```
| 字段 | 类型 | 说明 |
| ---- | ---- | ---- |
| clientAgent | array | 在线 Agent 设备列表 |
| clientWeb | array | 在线 Web 订阅列表 |
| online | int | 总在线连接数 |
### 16.3 查询监控图表数据
- **请求方式**:`POST /monitor/chart/query`
- **请求体** `MonitorChartQueryVo`:
| 字段 | 类型 | 必填 | 说明 |
| ---- | ---- | ---- | ---- |
| deviceId | string | 否 | 设备ID |
| startTime | datetime | 否 | 开始时间 |
| endTime | datetime | 否 | 结束时间 |
| hours | int | 否 | 时间范围(小时),默认 1 |
- **返回 `data`**:`MonitorChartVo`
```json
{
"timeLabels": ["14:00", "14:01"],
"cpu": { "load": [], "clock": [], "voltage": [] },
"gpu": { "load": [], "memoryLoad": [], "coreClock": [], "memoryClock": [], "vramUsed": [], "vramTotal": [] },
"memory": { "load": [], "used": [], "free": [] },
"temp": { "cpuPackage": [], "cpuAvg": [], "cpuMax": [], "gpu": [], "gpuHotspot": [] },
"power": { "cpu": [] },
"fan": { "gpuSpeed": [], "gpuLoad": [] }
}
```
| 字段 | 说明 |
| ---- | ---- |
| timeLabels | 时间轴标签 |
| cpu | CPU 使用率/频率/电压 |
| gpu | GPU 使用率/显存/核心与显存频率/显存占用 |
| memory | 内存使用率/已用/剩余 |
| temp | CPU 封装、平均、最高温度与 GPU/热点温度 |
| power | CPU 功耗 |
| fan | GPU 风扇转速与负载 |
---
## 附录:状态码说明
| code | 含义 |
| ---- | ---- |
| 200 | 成功 |
| 400 | 参数错误 / 业务校验失败 |
| 401 | 未认证(Token 缺失或无效) |
| 403 | 无权限 |
| 500 | 服务端错误 / 业务异常 |
> 注:`ResponseResult` 中 `data` 为 `null` 时该字段不参与序列化;文中标注"(注意:使用 GET)"的接口为代码现状,勿照常规语义调用。