Files
turing_alert_web/AGENTS.md
2026-06-10 11:46:45 +08:00

313 lines
10 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.
# AGENTS.md
本文档包含针对此 Vue 3 + TypeScript 本地告警管理应用的智能编码代理指南。
## 开发命令
| 命令 | 说明 |
|------|------|
| `npm install` | 安装依赖 |
| `npm run dev` | 启动热重载开发服务器8000端口 |
| `npm run build` | 构建生产版本(包含类型检查) |
| `npm run type-check` | 仅运行 TypeScript 类型检查 |
| `npm run preview` | 本地预览生产构建 |
> 本项目目前未配置测试框架。
## 项目结构
```
src/
├── components/ # 可复用 Vue 组件
├── html/ # 页面级 Vue 组件
├── utils/ # 工具函数和 API
│ ├── boxApi.ts # 主 API 接口
│ ├── useGlobalWebSocket.ts # WebSocket 管理
│ ├── crossWindowChannel.ts # 跨窗口通信
│ └── eventBus.ts # 事件总线mitt
├── router/ # Vue Router 配置
└── stores/ # Pinia 状态管理
```
## 代码风格指南
### TypeScript
- 路径别名:`@/` 映射到 `src/`
- 始终为 props 和数据接口添加类型
### Vue 组件
- 使用 `<script setup>` 组合式 API
- 使用 `defineProps<T>()``defineEmits<T>()`
### 导入顺序
```typescript
// 1. Vue 导入
import { ref, computed, onMounted } from 'vue'
// 2. 第三方库
import axios from 'axios'
import { ElMessage } from 'element-plus'
// 3. 内部导入(@ 别名)
import { BoxApi } from '@/utils/boxApi'
```
### 命名规范
| 类型 | 规范 | 示例 |
|------|------|------|
| 组件 | PascalCase | `CameraRules.vue` |
| 变量 | camelCase | `selectedAlerts` |
| 常量 | UPPER_SNAKE_CASE | `MAX_COUNT` |
| 函数 | fetch/handle/format 前缀 | `fetchEvents` |
### 错误处理
- 异步操作使用 try-catch
- 使用 `ElMessage.error()` 显示错误
- 在 axios 拦截器中处理 401 响应
## 常用模式
### 跨窗口通信
```typescript
import { broadcast, onCrossWindowMessage } from '@/utils/crossWindowChannel'
// 发送
broadcast.sendDialog(data)
// 接收
onCrossWindowMessage((msg) => { /* 处理 */ })
```
### 事件总线
```typescript
import eventBus from '@/utils/eventBus'
eventBus.emit('showDialog', data)
eventBus.on('showDialog', (data) => { /* 处理 */ })
```
### 告警列表导出(支持跨页勾选)
```typescript
// 选中导出selectedAlerts.value 存储勾选的 ID
// 无勾选:导出当前筛选条件下的所有数据
```
## 注意事项
- 这是一个安防摄像头告警管理系统
- 中文 UI 文本是有意保留的
- 跨窗口通信使用 BroadcastChannel需同源策略
- WebSocket 连接地址:`ws://192.168.28.32:8080/ws/event`
- API 基础地址:`http://192.168.28.32:8000/api/v1`
## 补充说明:
event接口
GET请求/api/v1/event
响应体如下:
```
{
"err": {
"ec": 0,
"dm": "ok"
},
"ret": {
"count": 1617,
"next": "http://127.0.0.1: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://127.0.0.1:8000/media/mediums/2026/04/02/camera1_1775035800_wander_OHtwpT0.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": [
{
"id": 1,
"unique_id": "1268f3f2-e0c5-47ea-aa1f-5b97b6dfb95d",
"camera": 1,
"name": "徘徊",
"mode": "on",
"algo": "wander",
"params": {},
"params_base": "",
"schedule": {},
"event_types": {
"wander": "人员徘徊"
}
},
{
"id": 32,
"unique_id": "9c5e2f2d-4d0e-4ca7-97ee-866462664f8e",
"camera": 1,
"name": "入侵",
"mode": "on",
"algo": "intrusion",
"params": {},
"params_base": "",
"schedule": {},
"event_types": {
"intrusion": "入侵"
}
},
{
"id": 35,
"unique_id": "fdd29eaa-c07a-43c4-ad6c-171d9dfadcf4",
"camera": 1,
"name": "未穿反光衣",
"mode": "on",
"algo": "no_reflective_clothing",
"params": {},
"params_base": "",
"schedule": {},
"event_types": {
"no_reflective_clothing": "未佩戴反光衣"
}
}
],
"should_push": false,
"config_params": {},
"sampling": false,
"note": {},
"snapshot": "http://127.0.0.1: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": {}
}]
```
## 本次修改记录2026年4月
### 问题描述
部署到服务器后,前端通过 HTTPS 访问 (`https://192.168.28.32`),但后端返回的 JSON 数据中包含内部地址(如 `http://127.0.0.1:8000/media/...`),导致:
1. **图片无法显示** - 告警列表、详情、通道预览图等全部异常
2. **分页 next/previous URL 异常** - 指向 `http://127.0.0.1:8000/...`
3. **Channel/CenterTop 摄像头预览图异常** - `http://127.0.0.1:8000/media/camera/...`
### 问题原因
后端 Django 在内部请求自己的 API 时,返回的 JSON 数据中使用的是内部地址 `127.0.0.1:8000`,而不是前端实际访问的服务器地址。
### 解决方案
`boxApi.ts` 中添加 `normalizeBackendUrls` 方法,将后端返回的 URL 统一转换为正确地址。
### 修改原理
```typescript
private normalizeBackendUrls(data: any): any {
// 强制使用 http + 8000 端口
const baseUrl = `http://${window.location.hostname}:8000`;
const replaceHost = (url: string | null | undefined): string | null => {
if (!url) return null;
return url
.replace(/https?:\/\/127\.0\.0\.1(?::8000)?/gi, baseUrl)
.replace(/https?:\/\/localhost(?::8000)?/gi, baseUrl);
};
// 处理多种数据格式...
}
```
**转换示例**
- `http://127.0.0.1:8000/media/xxx.jpg``http://192.168.28.32:8000/media/xxx.jpg`
- `http://localhost:8000/media/xxx.jpg``http://192.168.28.32:8000/media/xxx.jpg`
### 修改的文件
| 文件 | 修改内容 |
|------|---------|
| `src/utils/boxApi.ts` | 添加 normalizeBackendUrls 方法,在多个 API 接口中调用 |
| `src/utils/superboxApi.ts` | 添加 URL 规范化支持(备用) |
| `src/components/Cameras.vue` | 修复硬编码 IP `192.168.28.33` |
| `vite.config.ts` | 添加 /media 和 /ws 代理配置 |
### 已修复的接口
| 接口方法 | 返回数据 | 处理的字段 |
|---------|---------|-----------|
| `getEvents` | 事件列表 | `results[].mediums[].file`, `results[].camera.snapshot` |
| `getEventsByParams` | 事件列表 | 同上 + `next`, `previous` 分页链接 |
| `getEventsByUrl` | 事件列表 | 同上 |
| `getEventById` | 单个事件 | `mediums[].file`, `camera.snapshot` |
| `getAllCameras` | 摄像头列表 | `[].snapshot` |
| `getCameraById` | 单个摄像头 | `.snapshot` |
### 视频点播WebSocket说明
- **接口**`startCameraStream` 返回动态端口(如 8094
- **连接方式**:前端直接连接 `ws://192.168.28.32:8094/`
- **限制**:需要服务器开放对应端口,或配置 Apache 动态代理
- **Vite 代理**:仅开发环境有效,部署后需服务器端配置
### Vite 开发代理配置
开发环境代理配置(`vite.config.ts`
```typescript
proxy: {
'/api': {
target: 'http://192.168.28.32:8000',
changeOrigin: true,
},
'/media': {
target: 'http://192.168.28.32:8000',
changeOrigin: true,
},
'/ws': {
target: 'ws://192.168.28.32:8080',
ws: true,
}
}
```
**注意**此配置仅开发环境有效部署后需配置服务器端代理Apache/Nginx
### API 统一使用说明
- 项目统一使用 `BoxApi` 类进行 API 调用
- `SuperboxApi` 为遗留代码,未被页面使用
- 所有页面通过 `new BoxApi()` 创建实例调用接口
### 通道视频安全模式观看方式
> chrome://flags/#unsafely-treat-insecure-origin-as-secure非安全模式在可开启通知权限
- 权限开启允许不安全文件