Files
iot-device-management-service/docs/芋道前端对接文档.md
16337 12e127f1f0 docs: 添加告警平台与芋道前端对接文档
包含以下内容:
- 后端 API 接口详细说明
- 芋道前端集成步骤
- 边缘端对接示例代码
- 阿里云 OSS 配置说明
- 大模型分析配置(可选)
- 部署说明
2026-02-02 09:44:05 +08:00

532 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AI 告警平台与芋道前端对接文档
> 本文档指导如何在芋道前端项目yudao-ui-admin-vben中集成告警平台功能。
## 一、项目概述
### 1.1 告警平台后端
- **技术栈**: FastAPI + SQLite + 阿里云 OSS
- **职责**: 接收边缘端告警、存储告警证据、提供 REST API
- **端口**: 8000
### 1.2 芋道前端
- **技术栈**: Vue 3 + Vben Admin + Ant Design Vue
- **职责**: 告警列表展示、详情查看、人工处理
- **复用**: 用户体系、权限管理、页面布局
---
## 二、后端 API 接口
### 2.1 基础信息
- **Base URL**: `http://localhost:8000`
- **文档地址**: `http://localhost:8000/docs`
### 2.2 接口列表
#### 2.2.1 健康检查
```http
GET /health
```
**响应**:
```json
{
"status": "healthy",
"database": "healthy"
}
```
#### 2.2.2 创建告警(边缘端调用)
```http
POST /api/v1/alerts
Content-Type: multipart/form-data
```
**请求参数**:
- `data` (FormField): JSON 字符串
```json
{
"camera_id": "cam-001",
"roi_id": "roi-01",
"alert_type": "leave_post",
"algorithm": "LeavePostAlgorithm",
"confidence": 85,
"duration_minutes": 5,
"trigger_time": "2024-01-20T10:30:00Z",
"message": "离岗告警"
}
```
- `snapshot` (File, 可选): 告警抓拍图片
**响应**:
```json
{
"id": 1,
"alert_no": "ALT20240120103000ABC12345",
"camera_id": "cam-001",
"roi_id": "roi-01",
"alert_type": "leave_post",
"algorithm": "LeavePostAlgorithm",
"confidence": 85,
"duration_minutes": 5,
"trigger_time": "2024-01-20T10:30:00Z",
"message": "离岗告警",
"snapshot_url": "https://your-bucket.oss-cn-hangzhou.aliyuncs.com/alerts/xxx.jpg",
"status": "pending",
"created_at": "2024-01-20T10:30:00Z"
}
```
#### 2.2.3 查询告警列表
```http
GET /api/v1/alerts
```
**查询参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| cameraId | string | 否 | 摄像头ID |
| alertType | string | 否 | 告警类型 |
| status | string | 否 | 处理状态 |
| startTime | datetime | 否 | 开始时间 |
| endTime | datetime | 否 | 结束时间 |
| page | int | 否 | 页码默认1 |
| pageSize | int | 否 | 每页条数默认20 |
**响应**:
```json
{
"alerts": [...],
"total": 100,
"page": 1,
"pageSize": 20
}
```
#### 2.2.4 获取告警详情
```http
GET /api/v1/alerts/{alertId}
```
#### 2.2.5 处理告警
```http
PUT /api/v1/alerts/{alertId}/handle
```
**请求体**:
```json
{
"status": "confirmed",
"remark": "确认为真实告警"
}
```
**状态枚举**: `pending` | `confirmed` | `ignored` | `resolved`
#### 2.2.6 获取告警统计
```http
GET /api/v1/alerts/statistics
```
**响应**:
```json
{
"total": 100,
"pending": 10,
"confirmed": 50,
"ignored": 20,
"resolved": 20,
"by_type": {
"leave_post": 80,
"intrusion": 20
}
}
```
---
## 三、芋道前端集成步骤
### 3.1 创建 API 文件
在 `apps/web-antd/src/api/` 目录下创建 `alert` 目录,并添加 `alert.ts`:
```typescript
import { requestClient } from '#/api/request';
export namespace AlertApi {
export interface Alert {
id: number;
alertNo: string;
cameraId: string;
roiId?: string;
alertType: string;
algorithm?: string;
confidence?: number;
durationMinutes?: number;
triggerTime: string;
message?: string;
snapshotUrl?: string;
status: 'pending' | 'confirmed' | 'ignored' | 'resolved';
handleRemark?: string;
handledBy?: string;
handledAt?: string;
aiAnalysis?: Record<string, any>;
createdAt: string;
updatedAt: string;
}
export interface AlertListParams {
pageNo: number;
pageSize: number;
cameraId?: string;
alertType?: string;
status?: string;
startTime?: string;
endTime?: string;
}
export interface AlertListResponse {
alerts: Alert[];
total: number;
page: number;
pageSize: number;
}
export interface AlertStatistics {
total: number;
pending: number;
confirmed: number;
ignored: number;
resolved: number;
by_type: Record<string, number>;
}
export interface HandleAlertRequest {
status: 'confirmed' | 'ignored' | 'resolved';
remark?: string;
}
}
export function getAlertList(params: AlertApi.AlertListParams) {
return requestClient.get<AlertApi.AlertListResponse>('/api/v1/alerts', {
params,
});
}
export function getAlertDetail(alertId: number) {
return requestClient.get<AlertApi.Alert>(`/api/v1/alerts/${alertId}`);
}
export function handleAlert(alertId: number, data: AlertApi.HandleAlertRequest) {
return requestClient.put<AlertApi.Alert>(`/api/v1/alerts/${alertId}/handle`, data, {
params: { handledBy: 'currentUser' },
});
}
export function getAlertStatistics() {
return requestClient.get<AlertApi.AlertStatistics>('/api/v1/alerts/statistics');
}
```
### 3.2 创建路由配置
在 `apps/web-antd/src/router/routes/modules/` 下创建 `alert.ts`:
```typescript
import type { RouteRecordRaw } from 'vue-router';
const routes: RouteRecordRaw[] = [
{
path: '/alert',
name: 'AlertCenter',
meta: {
title: '告警中心',
icon: 'lucide:bell',
keepAlive: true,
},
children: [
{
path: 'list',
name: 'AlertList',
meta: {
title: '告警列表',
noCache: true,
},
component: () => import('#/views/alert/list/index.vue'),
},
],
},
];
export default routes;
```
将此路由添加到主路由配置中(编辑 `apps/web-antd/src/router/routes/modules/` 下的 `dashboard.ts` 或其他菜单配置)。
### 3.3 创建页面组件
在 `apps/web-antd/src/views/` 下创建 `alert/list/` 目录:
**data.ts**:
```typescript
import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { getRangePickerDefaultProps } from '#/utils';
export function useAlertFormSchema(): VbenFormSchema[] {
return [
{ fieldName: 'cameraId', label: '摄像头ID', component: 'Input', componentProps: { placeholder: '请输入摄像头ID', allowClear: true } },
{ fieldName: 'alertType', label: '告警类型', component: 'Input', componentProps: { placeholder: '请输入告警类型', allowClear: true } },
{
fieldName: 'status',
label: '处理状态',
component: 'Select',
componentProps: {
options: [
{ label: '待处理', value: 'pending' },
{ label: '已确认', value: 'confirmed' },
{ label: '已忽略', value: 'ignored' },
{ label: '已解决', value: 'resolved' },
],
placeholder: '请选择处理状态',
allowClear: true,
},
},
{ fieldName: 'createTime', label: '创建时间', component: 'RangePicker', componentProps: { ...getRangePickerDefaultProps(), allowClear: true } },
];
}
export function useAlertColumns(): VxeTableGridOptions['columns'] {
return [
{ type: 'checkbox', width: 40 },
{ field: 'id', title: '编号', minWidth: 80 },
{ field: 'alertNo', title: '告警编号', minWidth: 150 },
{ field: 'cameraId', title: '摄像头', minWidth: 100 },
{ field: 'alertType', title: '告警类型', minWidth: 100 },
{ field: 'algorithm', title: '算法', minWidth: 120 },
{ field: 'confidence', title: '置信度', minWidth: 80, slots: { default: 'confidence' } },
{ field: 'durationMinutes', title: '离岗时长', minWidth: 100, slots: { default: 'duration' } },
{ field: 'status', title: '状态', minWidth: 100, slots: { default: 'status' } },
{ field: 'createdAt', title: '创建时间', minWidth: 180, formatter: 'formatDateTime' },
{ title: '操作', width: 150, fixed: 'right', slots: { default: 'actions' } },
];
}
```
**index.vue**:
参考芋道现有的 IoT 告警页面 `apps/web-antd/src/views/iot/alert/record/index.vue` 进行修改。
---
## 四、边缘端对接示例
### 4.1 Python (ai_edge 项目)
在 `ai_edge` 项目的 `main.py` 中添加告警上报功能:
```python
import requests
from datetime import datetime
class AlertReporter:
ALERT_PLATFORM_URL = "http://localhost:8000/api/v1/alerts"
def report_alert(
self,
camera_id: str,
roi_id: str,
alert_type: str,
algorithm: str,
confidence: float,
duration_minutes: int,
message: str,
screenshot: bytes,
):
alert_data = {
"camera_id": camera_id,
"roi_id": roi_id,
"alert_type": alert_type,
"algorithm": algorithm,
"confidence": int(confidence * 100),
"duration_minutes": duration_minutes,
"trigger_time": datetime.utcnow().isoformat() + "Z",
"message": message,
}
files = {
"snapshot": ("alert.jpg", screenshot, "image/jpeg"),
"data": (None, json.dumps(alert_data), "application/json"),
}
response = requests.post(self.ALERT_PLATFORM_URL, files=files)
response.raise_for_status()
return response.json()
```
### 4.2 在推理服务中调用
在 `EdgeInferenceService._handle_detections` 方法中调用:
```python
def _handle_detections(self, camera_id: str, roi, frame: VideoFrame, alerts: list):
for alert in alerts:
# 上报到云端告警平台
self._reporter.report_to_platform(
camera_id=camera_id,
roi_id=roi.roi_id,
alert_type=alert.get("alert_type"),
algorithm="LeavePostAlgorithm",
confidence=alert.get("confidence", 1.0),
duration_minutes=alert.get("duration_minutes", 0),
message=alert.get("message", ""),
screenshot=frame.image,
)
```
---
## 五、阿里云 OSS 配置
### 5.1 配置项
在告警平台的 `.env` 文件中配置:
```env
OSS_ACCESS_KEY_ID=your_access_key_id
OSS_ACCESS_KEY_SECRET=your_access_key_secret
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
OSS_BUCKET_NAME=your_bucket_name
OSS_URL_PREFIX=https://your-bucket-name.oss-cn-hangzhou.aliyuncs.com
```
### 5.2 权限要求
OSS Bucket 需要配置以下权限:
- **CORS**: 允许前端跨域访问
- **公共读**: 告警图片需要可以公开访问
---
## 六、大模型分析配置(可选)
### 6.1 配置项
```env
AI_MODEL_ENDPOINT=http://localhost:8001
AI_MODEL_API_KEY=your_api_key
```
### 6.2 大模型 API 格式
告警平台期望大模型服务提供以下接口:
```http
POST /analyze
Content-Type: application/json
{
"alert_id": 1,
"snapshot_url": "https://xxx/alert.jpg",
"alert_info": {
"camera_id": "cam-001",
"roi_id": "roi-01",
"alert_type": "leave_post",
"confidence": 85,
"duration_minutes": 5
}
}
```
**响应格式**:
```json
{
"risk_level": "HIGH",
"description": "检测到人员在非工作区域长时间停留,建议现场核实",
"suggestion": "可能是误报,建议确认监控区域工作安排",
"confidence_score": 0.92
}
```
---
## 七、部署说明
### 7.1 后端部署
```bash
# 1. 安装依赖
pip install -r requirements.txt
# 2. 配置环境变量
cp .env.example .env
# 编辑 .env 文件
# 3. 启动服务
python -m app.main
```
### 7.2 使用 Gunicorn 生产部署
```bash
gunicorn app.main:app -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000
```
### 7.3 Docker 部署
创建 `Dockerfile`:
```dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "-m", "app.main"]
```
---
## 八、注意事项
1. **芋道项目权限**: 告警相关接口需要芋道后端配合实现用户认证
2. **跨域配置**: 告警平台需要配置 CORS 以允许芋道前端访问
3. **图片存储**: 阿里云 OSS 需要配置 CORS 允许前端直接访问图片
4. **时区处理**: 建议统一使用 UTC 时间,前端展示时转换为本地时间
5. **大模型服务**: AI 分析功能可选,需要部署大模型服务支持
---
## 九、目录结构总结
```
# 告警平台后端
alert_platform/
├── app/
│ ├── main.py # FastAPI 入口
│ ├── config.py # 配置
│ ├── models.py # SQLAlchemy 模型
│ ├── schemas.py # Pydantic 模型
│ ├── services/
│ │ ├── alert_service.py # 告警业务逻辑
│ │ ├── oss_storage.py # OSS 存储
│ │ └── ai_analyzer.py # AI 分析
│ └── utils/
│ └── logger.py # 日志
├── data/ # SQLite 数据库
├── uploads/ # 本地临时存储
├── requirements.txt
├── .env.example
└── README.md
# 芋道前端需要创建的文件
yudao-ui-admin-vben/
└── apps/web-antd/src/
├── api/
│ └── alert/
│ └── alert.ts # 告警 API
├── router/routes/modules/
│ └── alert.ts # 告警路由
└── views/alert/
└── list/
├── data.ts # 列表配置
└── index.vue # 列表页面
```