1187 lines
27 KiB
Markdown
1187 lines
27 KiB
Markdown
# 告警管理系统 API 接口文档(Django 版)
|
||
|
||
> 基础路径:`/api/v1`
|
||
> 服务器地址:`http://192.168.28.32:8000`
|
||
> 认证方式:Bearer Token(24h 有效期)
|
||
> 统一响应信封:`{ "err": { "ec": 0, "dm": "ok" }, "ret": <data> }`
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [认证接口](#1-认证接口)
|
||
2. [事件(告警)接口](#2-事件告警接口)
|
||
3. [摄像头接口](#3-摄像头接口)
|
||
4. [规则接口](#4-规则接口)
|
||
5. [算法接口](#5-算法接口)
|
||
6. [WebSocket 接口](#6-websocket-接口)
|
||
7. [通用响应格式](#7-通用响应格式)
|
||
8. [认证与 Token 管理](#8-认证与-token-管理)
|
||
9. [前端数据转换说明](#9-前端数据转换说明)
|
||
10. [完整调用示例](#10-完整调用示例)
|
||
11. [附录:前端 API 方法速查表](#11-附录前端-api-方法速查表)
|
||
|
||
---
|
||
|
||
## 1. 认证接口
|
||
|
||
---
|
||
|
||
### 1.1 登录
|
||
|
||
- **方法**:`POST`
|
||
- **路径**:`/auth/login`
|
||
- **描述**:用户登录,获取 Token
|
||
- **鉴权**:无(公开)
|
||
|
||
**请求头**:
|
||
```http
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**请求体(Body JSON)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `username` | `string` | 是 | 用户名 |
|
||
| `password` | `string` | 是 | 密码 |
|
||
| `cookieless` | `string` | 是 | `"True"` 或 `"False"` |
|
||
|
||
```json
|
||
{
|
||
"username": "admin",
|
||
"password": "123456",
|
||
"cookieless": "False"
|
||
}
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {
|
||
"token": "eyJhbGciOiJIUzI1NiIs..."
|
||
}
|
||
}
|
||
```
|
||
|
||
| 返回字段 | 类型 | 说明 |
|
||
|---------|------|------|
|
||
| `ret.token` | `string` | JWT Token,有效期 24h |
|
||
|
||
**失败响应**:
|
||
```json
|
||
{
|
||
"err": { "ec": 1001, "dm": "用户名或密码错误" }
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 1.2 登出
|
||
|
||
- **方法**:`POST`
|
||
- **路径**:`/auth/logout`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**请求体**:无
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 1.3 添加用户
|
||
|
||
- **方法**:`POST`
|
||
- **路径**:`/auth/adduser`
|
||
- **鉴权**:Bearer Token(需管理员权限)
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**请求体(Body JSON)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `username` | `string` | 是 | 用户名 |
|
||
| `password` | `string` | 是 | 密码 |
|
||
| `email` | `string` | 否 | 邮箱,默认为空 |
|
||
|
||
```json
|
||
{
|
||
"username": "operator1",
|
||
"password": "pass123456",
|
||
"email": ""
|
||
}
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 1.4 删除用户
|
||
|
||
- **方法**:`POST`
|
||
- **路径**:`/auth/rmuser`
|
||
- **鉴权**:Bearer Token(需管理员权限)
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**请求体(Body JSON)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `username` | `string` | 是 | 要删除的用户名 |
|
||
|
||
```json
|
||
{
|
||
"username": "operator1"
|
||
}
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 1.5 获取所有用户
|
||
|
||
- **方法**:`GET`
|
||
- **路径**:`/auth/allusers`
|
||
- **鉴权**:Bearer Token(需管理员权限)
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**请求参数**:无
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {
|
||
"users": [
|
||
{
|
||
"username": "admin",
|
||
"email": ""
|
||
},
|
||
{
|
||
"username": "operator1",
|
||
"email": "op1@example.com"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
| 返回字段 | 类型 | 说明 |
|
||
|---------|------|------|
|
||
| `ret.users` | `array` | 用户列表 |
|
||
| `ret.users[].username` | `string` | 用户名 |
|
||
| `ret.users[].email` | `string` | 邮箱 |
|
||
|
||
---
|
||
|
||
### 1.6 重置用户信息
|
||
|
||
- **方法**:`POST`
|
||
- **路径**:`/auth/resetuser`
|
||
- **鉴权**:Bearer Token(需管理员权限)
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**请求体(Body JSON)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `username` | `string` | 是 | 用户名 |
|
||
| `password` | `string` | 是 | 新密码 |
|
||
| `email` | `string` | 是 | 邮箱 |
|
||
|
||
```json
|
||
{
|
||
"username": "operator1",
|
||
"password": "newpass123",
|
||
"email": "op1@example.com"
|
||
}
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {}
|
||
}
|
||
```
|
||
|
||
|
||
---
|
||
|
||
## 2. 事件(告警)接口
|
||
|
||
---
|
||
|
||
### 2.1 获取事件列表(分页)
|
||
|
||
- **方法**:`GET`
|
||
- **路径**:`/events`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**查询参数(Query)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||
|--------|------|------|--------|------|
|
||
| `limit` | `number` | 否 | `20` | 每页条数 |
|
||
| `offset` | `number` | 否 | `0` | 偏移量 |
|
||
|
||
**请求示例**:
|
||
```
|
||
GET /api/v1/events?limit=20&offset=0
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {
|
||
"count": 1617,
|
||
"next": "http://192.168.28.32:8000/api/v1/events?limit=20&offset=20",
|
||
"previous": null,
|
||
"results": [
|
||
{
|
||
"id": 90908,
|
||
"camera_id": 1,
|
||
"started_at": "2026-04-01T09:30:00Z",
|
||
"ended_at": "2026-04-01T09:30:10Z",
|
||
"mediums": [
|
||
{
|
||
"id": 109656,
|
||
"name": "snapshot",
|
||
"file": "http://192.168.28.32:8000/media/mediums/2026/04/02/camera1_xxx.jpg",
|
||
"event_id": 90908
|
||
}
|
||
],
|
||
"camera": {
|
||
"id": 1,
|
||
"name": "421枪机",
|
||
"uri": "rtsp://admin:1234qwer@192.168.28.102:554/Streaming/Channels/202",
|
||
"mode": "on",
|
||
"status": "online",
|
||
"detect_params": { "threshold": 0.5 },
|
||
"default_params": {},
|
||
"rules": [ /* RuleItem[] 见规则结构 */ ],
|
||
"should_push": false,
|
||
"config_params": {},
|
||
"sampling": false,
|
||
"note": {},
|
||
"snapshot": "http://192.168.28.32:8000/media/camera/camera1_snapshot.jpg",
|
||
"remote_id": -1,
|
||
"raw_address": "0b8342ec52e62d01dd3273f583d326ec",
|
||
"ip": "admin:1234qwer@192.168.28.102:554",
|
||
"port": 8082
|
||
},
|
||
"types": "wander",
|
||
"types_bits": 0,
|
||
"obj_types": {},
|
||
"uuid": "461aeb6e-10f3-4173-9b33-d540ce59511e",
|
||
"status": "pending",
|
||
"remark": null,
|
||
"should_push": false,
|
||
"metadata": {}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**前端返回**:
|
||
```typescript
|
||
{
|
||
tableData: EventItem[], // ret.results
|
||
totalItems: number // ret.count
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2.2 按参数筛选事件列表
|
||
|
||
- **方法**:`GET`
|
||
- **路径**:`/events`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**查询参数(Query)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||
|--------|------|------|--------|------|
|
||
| `limit` | `number` | 否 | `20` | 每页条数 |
|
||
| `offset` | `number` | 否 | `0` | 偏移量 |
|
||
| `time_before` | `string` | 否 | — | 结束时间(ISO 8601) |
|
||
| `time_after` | `string` | 否 | — | 开始时间(ISO 8601) |
|
||
| `types` | `string` | 否 | — | 告警类型编码(如 `wander`) |
|
||
| `camera_id` | `number` | 否 | — | 摄像头 ID |
|
||
| `status` | `string` | 否 | — | 状态:`pending` / `closed` |
|
||
|
||
**请求示例**:
|
||
```
|
||
GET /api/v1/events?limit=20&offset=0&time_after=2026-04-01T00%3A00%3A00Z&time_before=2026-04-02T00%3A00%3A00Z&types=wander&camera_id=1&status=pending
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
**成功响应(200 OK)**:同 2.1 响应结构。
|
||
|
||
---
|
||
|
||
|
||
|
||
---
|
||
|
||
### 2.3 获取单个事件详情
|
||
|
||
- **方法**:`GET`
|
||
- **路径**:`/event/events/retrieves`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**查询参数(Query)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `id` | `number` | 是 | 事件 ID |
|
||
|
||
**请求示例**:
|
||
```
|
||
GET /api/v1/event/events/retrieves?id=90908
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {
|
||
"objects": [
|
||
{
|
||
"id": 90908,
|
||
"camera_id": 1,
|
||
"started_at": "2026-04-01T09:30:00Z",
|
||
"ended_at": "2026-04-01T09:30:10Z",
|
||
"mediums": [
|
||
{
|
||
"id": 109656,
|
||
"name": "snapshot",
|
||
"file": "http://192.168.28.32:8000/media/mediums/2026/04/02/camera1_xxx.jpg",
|
||
"event_id": 90908
|
||
}
|
||
],
|
||
"camera": { /* CameraItem 见摄像头结构 */ },
|
||
"types": "wander",
|
||
"types_bits": 0,
|
||
"obj_types": {},
|
||
"uuid": "461aeb6e-10f3-4173-9b33-d540ce59511e",
|
||
"status": "pending",
|
||
"remark": null,
|
||
"should_push": false,
|
||
"metadata": {}
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**前端取值**:`res.data.ret.objects[0]`
|
||
|
||
---
|
||
|
||
### 2.4 获取最新一条事件
|
||
|
||
- **方法**:内部调用 `getEvents(token, 1, 1)`
|
||
- **路径**:`/events?limit=1&offset=0`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**成功响应**:同 2.1,但 `results` 只有一条,`count` 为总条数。
|
||
|
||
---
|
||
|
||
### 2.5 修改事件状态
|
||
|
||
- **方法**:`PATCH`
|
||
- **路径**:`/events/{eventId}`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `eventId` | `number` | 事件 ID |
|
||
|
||
**请求体(Body JSON)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `status` | `string` | 是 | 状态值:`pending` / `closed` |
|
||
| `remark` | `string` | 否 | 备注信息 |
|
||
|
||
```json
|
||
{
|
||
"status": "closed",
|
||
"remark": "已处理完毕"
|
||
}
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 2.6 删除事件
|
||
|
||
- **方法**:`DELETE`
|
||
- **路径**:`/event/events/{eventId}`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `eventId` | `number` | 事件 ID |
|
||
|
||
**请求体**:无
|
||
|
||
**成功响应**:`204 No Content`(无 body)
|
||
|
||
**失败响应**(如事件不存在):
|
||
```json
|
||
{
|
||
"err": {
|
||
"ec": 404,
|
||
"dm": "Not Found",
|
||
"em": "Not found."
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
### 2.7 事件对象完整结构(EventItem)
|
||
|
||
```typescript
|
||
interface EventItem {
|
||
id: number; // 告警 ID
|
||
camera_id: number; // 摄像头 ID
|
||
started_at: string; // 开始时间(ISO 8601)
|
||
ended_at: string; // 结束时间(ISO 8601)
|
||
types: string; // 告警类型编码(如 "wander")
|
||
types_bits: number; // 类型位标记
|
||
obj_types: Record<string, any>; // 目标类型
|
||
uuid: string; // 唯一标识
|
||
status: 'pending' | 'closed'; // 处理状态
|
||
remark: string | null; // 备注
|
||
should_push: boolean; // 是否推送
|
||
metadata: Record<string, any>; // 元数据
|
||
|
||
// 多媒体
|
||
mediums: Array<{
|
||
id: number;
|
||
name: string; // 如 "snapshot"
|
||
file: string; // 图片 URL(已规范化)
|
||
event_id: number;
|
||
}>;
|
||
|
||
// 关联摄像头
|
||
camera: CameraItem;
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 摄像头接口
|
||
|
||
---
|
||
|
||
### 3.1 获取摄像头列表
|
||
|
||
- **方法**:`GET`
|
||
- **路径**:`/camera/cameras/get_all`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {
|
||
"count": 10,
|
||
"results": [
|
||
{
|
||
"id": 1,
|
||
"name": "421枪机",
|
||
"uri": "rtsp://{camerastream}",
|
||
"mode": "on",
|
||
"status": "online",
|
||
"detect_params": {
|
||
"threshold": 0.5
|
||
},
|
||
"default_params": {},
|
||
"rules": [
|
||
{
|
||
"id": 1,
|
||
"unique_id": "1268f3f2-e0c5-47ea-aa1f-5b97b6dfb95d",
|
||
"camera": 1,
|
||
"name": "规则名称",
|
||
"mode": "on",
|
||
"algo": "rule-name",
|
||
"params": {},
|
||
"params_base": "",
|
||
"schedule": {},
|
||
"event_types": {
|
||
"规则英文": "别名,中文映射"
|
||
}
|
||
}
|
||
],
|
||
"should_push": false,
|
||
"config_params": {},
|
||
"sampling": false,
|
||
"note": {},
|
||
"snapshot": "URL***.jpg",
|
||
"remote_id": -1,
|
||
"raw_address": "0b8342ec52e62d01dd3273f583d326ec",
|
||
"ip": "camera-url",
|
||
"port": 8082
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
|
||
|
||
---
|
||
|
||
### 3.2 获取单个摄像头详情
|
||
|
||
- **方法**:`GET`
|
||
- **路径**:`/camera/cameras/{cameraId}`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `cameraId` | `number` | 摄像头 ID |
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": { /* CameraItem */ }
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.3 更新摄像头信息
|
||
|
||
- **方法**:`PATCH`
|
||
- **路径**:`/camera/cameras/{cameraId}`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `cameraId` | `number` | 摄像头 ID |
|
||
|
||
**请求体(Body JSON)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `name` | `string` | 否 | 摄像头名称 |
|
||
| `mode` | `"on"` / `"off"` | 是 | 检测模式 |
|
||
|
||
```json
|
||
{
|
||
"name": "421枪机",
|
||
"mode": "on"
|
||
}
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": { /* CameraItem */ }
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.4 启动摄像头视频流
|
||
|
||
- **方法**:`POST`
|
||
- **路径**:`/camera/cameras/{cameraId}/start_stream`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `cameraId` | `number` | 摄像头 ID |
|
||
|
||
**请求体**:无
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {
|
||
"port": 8094
|
||
}
|
||
}
|
||
```
|
||
|
||
| 返回字段 | 类型 | 说明 |
|
||
|---------|------|------|
|
||
| `ret.port` | `number` | 动态分配的 WebSocket 端口,用于 JSMpeg 视频播放 |
|
||
|
||
---
|
||
|
||
### 3.5 停止摄像头视频流
|
||
|
||
- **方法**:`POST`
|
||
- **路径**:`/camera/cameras/{cameraId}/stop_stream`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `cameraId` | `number` | 摄像头 ID |
|
||
|
||
**请求体**:无
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": {}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 3.8 摄像头对象完整结构(CameraItem)
|
||
|
||
```typescript
|
||
interface CameraItem {
|
||
id: number;
|
||
name: string; // 点位名称(如 "421枪机")
|
||
uri: string; // RTSP 地址
|
||
mode: 'on' | 'off'; // 检测全局开关
|
||
status: 'online' | 'offline'; // 在线状态
|
||
detect_params: {
|
||
threshold: number; // 检测阈值(如 0.5)
|
||
};
|
||
default_params: Record<string, any>;
|
||
rules: RuleItem[]; // 关联规则列表
|
||
should_push: boolean;
|
||
config_params: Record<string, any>;
|
||
sampling: boolean;
|
||
note: Record<string, any>;
|
||
snapshot: string; // 快照图片 URL(已规范化)
|
||
remote_id: number;
|
||
raw_address: string;
|
||
ip: string;
|
||
port: number;
|
||
}
|
||
```
|
||
|
||
**前端发送的 CameraData 类型**(用于 updateCamera):
|
||
```typescript
|
||
interface CameraData {
|
||
id?: number;
|
||
name?: string;
|
||
mode?: "on" | "off";
|
||
rules?: RuleData[] | {};
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 规则接口
|
||
|
||
---
|
||
|
||
### 4.1 更新规则
|
||
|
||
- **方法**:`PATCH`
|
||
- **路径**:`/rules/{ruleId}`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
**路径参数**:
|
||
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| `ruleId` | `number` | 规则 ID |
|
||
|
||
**请求体(Body JSON)**:
|
||
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| `id` | `number` | 是 | 规则 ID |
|
||
| `name` | `string` | 否 | 规则名称 |
|
||
| `mode` | `"on"` / `"off"` / `"schedule"` | 否 | 规则模式 |
|
||
| `schedule` | `object` | 否 | 时间段配置 |
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"name": "徘徊",
|
||
"mode": "on",
|
||
"schedule": {}
|
||
}
|
||
```
|
||
|
||
**带时间段的请求**:
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"name": "未穿反光衣",
|
||
"mode": "schedule",
|
||
"schedule": {
|
||
"type": "daily",
|
||
"time_slots": [
|
||
[
|
||
960,
|
||
1020
|
||
]
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": { /* RuleItem */ }
|
||
}
|
||
```
|
||
|
||
|
||
|
||
---
|
||
|
||
### 4.2 规则对象完整结构(RuleItem)
|
||
|
||
```typescript
|
||
interface RuleItem {
|
||
id: number;
|
||
unique_id: string; // UUID
|
||
camera: number; // 关联摄像头 ID
|
||
name: string; // 规则名称(如 "徘徊")
|
||
mode: 'on' | 'off' | 'schedule';
|
||
algo: string; // 算法编码(如 "wander")
|
||
params: Record<string, any>;
|
||
params_base: string;
|
||
schedule: {
|
||
type: string; // 如 "daily"
|
||
time_slots?: Array<[number, number]>;
|
||
} | {};
|
||
event_types: Record<string, string>; // 如 { "wander": "人员徘徊" }
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 算法接口
|
||
|
||
---
|
||
|
||
### 5.1 获取算法列表
|
||
|
||
- **方法**:`GET`
|
||
- **路径**:`/algorithms`
|
||
- **鉴权**:Bearer Token
|
||
|
||
**请求头**:
|
||
```http
|
||
Authorization: Bearer <access_token>
|
||
Accept: application/json
|
||
```
|
||
|
||
**请求参数**:无
|
||
|
||
**成功响应(200 OK)**:
|
||
```json
|
||
{
|
||
"err": { "ec": 0, "dm": "ok" },
|
||
"ret": [
|
||
{ "code_name": "wander", "name": "人员徘徊" },
|
||
{ "code_name": "intrusion", "name": "入侵" },
|
||
{ "code_name": "no_reflective_clothing", "name": "未佩戴反光衣" }
|
||
]
|
||
}
|
||
```
|
||
|
||
| 返回字段 | 类型 | 说明 |
|
||
|---------|------|------|
|
||
| `ret[]` | `array` | 算法列表(无分页包装) |
|
||
| `ret[].code_name` | `string` | 算法编码(如 `wander`) |
|
||
| `ret[].name` | `string` | 算法中文名称(如 `人员徘徊`) |
|
||
|
||
### 5.2 算法映射表
|
||
|
||
```typescript
|
||
interface AlgorithmItem {
|
||
code_name: string; // 算法编码(如 "wander")
|
||
name: string; // 算法中文名称(如 "人员徘徊")
|
||
}
|
||
```
|
||
|
||
登录时自动拉取并构建 `Map<code_name, name>` 映射,供全局以编码查中文名。
|
||
|
||
---
|
||
|
||
## 6. WebSocket 接口
|
||
|
||
### 6.1 事件监听通道 WebSocket
|
||
|
||
- **地址**:`ws://192.168.28.32:8080/ws/event`
|
||
- **代理地址(Vite 开发环境)**:`/ws/event`
|
||
|
||
### 6.2 推送消息格式
|
||
|
||
```json
|
||
{
|
||
"id": 90908,
|
||
"camera_id": 1,
|
||
"started_at": "2026-04-01T09:30:00Z",
|
||
"ended_at": "2026-04-01T09:30:10Z",
|
||
"types": "wander",
|
||
"status": "pending",
|
||
"camera": { "id": 1, "name": "421枪机" },
|
||
"mediums": [ { "id": 109656, "name": "snapshot", "file": "http://192.168.28.32:8000/media/mediums/xxx.jpg" } ]
|
||
}
|
||
```
|
||
|
||
### 6.3 视频流 WebSocket
|
||
|
||
- **地址**:`ws://{host}:{dynamicPort}/`
|
||
- **说明**:由 `startCameraStream` 返回动态端口,JSMpeg 直接连接播放
|
||
|
||
---
|
||
|
||
## 7. 通用响应格式
|
||
|
||
### 7.1 成功响应
|
||
|
||
```json
|
||
{
|
||
"err": {
|
||
"ec": 0,
|
||
"dm": "ok"
|
||
},
|
||
"ret": { /* 响应数据 */ }
|
||
}
|
||
```
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `err.ec` | `number` | 错误码,`0` 表示成功 |
|
||
| `err.dm` | `string` | 状态描述,成功时为 `"ok"` |
|
||
| `ret` | `object` / `array` | 返回的数据主体 |
|
||
|
||
### 7.2 错误响应
|
||
|
||
```json
|
||
{
|
||
"err": {
|
||
"ec": 1001,
|
||
"dm": "错误描述信息"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 7.3 常见错误码
|
||
|
||
| 错误码 | 说明 |
|
||
|--------|------|
|
||
| `0` | 成功 |
|
||
| `1001` | 参数错误 |
|
||
| `1002` | 认证失败 |
|
||
| `1003` | 权限不足 |
|
||
| `1004` | 资源不存在 |
|
||
| `1005` | 操作失败 |
|
||
|
||
### 7.4 HTTP 状态码
|
||
|
||
| 状态码 | 说明 | 前端处理 |
|
||
|--------|------|----------|
|
||
| `200 OK` | 请求成功 | 正常处理 |
|
||
| `201 Created` | POST 创建成功 | 正常处理 |
|
||
| `204 No Content` | DELETE / 无业务数据 PATCH | 视作成功 |
|
||
| `400 Bad Request` | 参数错误 | 提示错误信息 |
|
||
| `401 Unauthorized` | 未授权 / Token 过期 | 清除 Token,跳转登录页 |
|
||
| `403 Forbidden` | 权限不足 | 提示无权限 |
|
||
| `404 Not Found` | 资源不存在 | 提示未找到 |
|
||
| `500 Internal Server Error` | 服务器内部错误 | 提示服务器错误 |
|
||
|
||
---
|
||
|
||
## 8. 认证与 Token 管理
|
||
|
||
### 8.1 Token 有效期
|
||
|
||
- Token 有效期:**24 小时**
|
||
- 前端每 **30 分钟** 检查一次 Token 是否过期
|
||
- 过期后自动清除 Token 并跳转到登录页
|
||
|
||
### 8.2 请求头格式
|
||
|
||
```http
|
||
Authorization: Bearer <token>
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
```
|
||
|
||
### 8.3 拦截器行为
|
||
|
||
- **请求拦截**:每次请求前检查 Token 是否过期(`checkTokenExpiry`)
|
||
- **响应拦截**:收到 `401` 状态码时自动清除 Token 并跳转登录
|
||
|
||
---
|
||
|
||
## 9. 前端数据转换说明
|
||
|
||
### 9.1 URL 规范化
|
||
|
||
后端返回的 JSON 中包含内部地址(如 `http://127.0.0.1:8000/media/...`),前端自动转换为:
|
||
- `http://127.0.0.1:8000/xxx` → `http://<实际服务器IP>:8000/xxx`
|
||
- `http://localhost:8000/xxx` → `http://<实际服务器IP>:8000/xxx`
|
||
|
||
适用字段:
|
||
- `mediums[].file`(事件图片)
|
||
- `camera.snapshot`(摄像头快照)
|
||
- 顶层 `snapshot` / `file`
|
||
- `next` / `previous` 分页链接
|
||
|
||
### 9.2 分页结构
|
||
|
||
所有列表接口统一分页格式:
|
||
```typescript
|
||
{
|
||
count: number, // 总条数
|
||
next: string|null, // 下一页 URL
|
||
previous: string|null, // 上一页 URL
|
||
results: T[] // 当前页数据
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 完整调用示例
|
||
|
||
### 10.1 登录并获取事件列表
|
||
|
||
```typescript
|
||
import { BoxApi } from '@/utils/boxApi';
|
||
|
||
const api = new BoxApi();
|
||
|
||
// 登录
|
||
const token = await api.login('admin', 'password');
|
||
|
||
// 获取事件(第1页,每页20条)
|
||
const { tableData, totalItems } = await api.getEvents(token, 20, 1);
|
||
|
||
// 按条件筛选
|
||
const { results, count } = await api.getEventsByParams(
|
||
token, 20, 1,
|
||
'2026-04-01T00:00:00Z', '2026-04-02T00:00:00Z',
|
||
'wander', null, 'pending'
|
||
);
|
||
|
||
// 获取所有摄像头
|
||
const cameras = await api.getAllCameras(token);
|
||
|
||
// 更新事件状态
|
||
await api.setEventStatus(90908, 'closed', '已处理', token);
|
||
|
||
// 删除事件
|
||
await api.delEvents(token, [90908, 90909]);
|
||
```
|
||
|
||
### 10.2 摄像头管理
|
||
|
||
```typescript
|
||
// 获取单个摄像头详情(含规则)
|
||
const camera = await api.getCameraById(token, 1);
|
||
|
||
// 更新摄像头基本设置
|
||
await api.updateCamera(token, 1, { name: '421枪机', mode: 'on' });
|
||
|
||
// 批量更新规则
|
||
await api.updateRule(token, [
|
||
{ id: 1, camera: 1, name: '徘徊', mode: 'on' },
|
||
{ id: 32, camera: 1, name: '入侵', mode: 'schedule', schedule: { type: 'daily', time_slots: [[480, 720]] } }
|
||
]);
|
||
|
||
// 启动视频流
|
||
const { port } = await api.startCameraStream(token, 1);
|
||
|
||
// 停止视频流
|
||
await api.stopCameraStream(token, 1);
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 附录:前端 API 方法速查表
|
||
|
||
| 方法 | HTTP 方法 | 路径 | 请求体/参数 | 响应体 |
|
||
|------|-----------|------|------------|--------|
|
||
| `login()` | POST | `/auth/login` | `{username, password, cookieless}` | `{token}` |
|
||
| `logout()` | POST | `/auth/logout` | 无 | `{}` |
|
||
| `addUser()` | POST | `/auth/adduser` | `{username, password, email?}` | `{}` |
|
||
| `rmUser()` | POST | `/auth/rmuser` | `{username}` | `{}` |
|
||
| `getAllUsers()` | GET | `/auth/allusers` | — | `{users: [...]}` |
|
||
| `resetUser()` | POST | `/auth/resetuser` | `{username, password, email}` | `{}` |
|
||
| `getEvents()` | GET | `/events?limit=&offset=` | — | `{count, next, prev, results}` |
|
||
| `getEventsByParams()` | GET | `/events?limit=&offset=&...` | — | `{count, next, prev, results}` |
|
||
| `getEventsByUrl()` | GET | 自定义 URL | — | `{count, next, prev, results}` |
|
||
| `getEventById()` | GET | `/event/events/retrieves?id=` | — | `{objects: [EventItem]}` |
|
||
| `getOneEvent()` | GET | `/events?limit=1&offset=0` | — | `{count, next, prev, results}` |
|
||
| `setEventStatus()` | PATCH | `/events/{id}` | `{status, remark?}` | `{}` |
|
||
| `delEvents()` | DELETE | `/event/events/{id}` | 无 | `[{id, success, message?}]` |
|
||
| `getCameras()` | GET | `/cameras?limit=&offset=` | — | `{count, results: [...]}` |
|
||
| `getCamerasByUrl()` | GET | 自定义 URL | — | `{count, results: [...]}` |
|
||
| `getAllCameras()` | GET | `/camera/cameras/get_all` | — | `CameraItem[]` |
|
||
| `getCameraById()` | GET | `/camera/cameras/{id}` | — | `CameraItem` |
|
||
| `updateCamera()` | PATCH | `/camera/cameras/{id}` | `{name, mode}` | `CameraItem` |
|
||
| `startCameraStream()` | POST | `/camera/cameras/{id}/start_stream` | 无 | `{port}` |
|
||
| `stopCameraStream()` | POST | `/camera/cameras/{id}/stop_stream` | 无 | `{}` |
|
||
| `updateRule()` | PATCH | `/rules/{id}` | `{id, camera, name?, mode?, schedule?}` | `RuleItem` |
|
||
| `getAlgorithms()` | GET | `/algorithms` | — | `AlgorithmItem[]` |
|
||
| `getAlgorithmName()` | — | 本地映射 | `code_name: string` | `string`(中文名) |
|