fix(alarm): 修复告警列表和汇总显示 camera_code 问题

问题:
- 告警列表和汇总页面显示 camera_code(例如 cam_1f0e3dad9990)而不是中文摄像头名称
- _get_camera_info 函数过早检查 token 导致查询失败

修复:
1. 移除 camera_code 查询路径中不必要的 token 检查
   - /api/ai/camera/get 已加入白名单,不需要认证
   - 仅对 app/stream 格式保留 token 检查

2. 修复告警列表页面摄像头名称显示
   - 将 _alarm_to_camel 改为 async 函数
   - 添加摄像头名称查询逻辑(三级 fallback)
   - 使用 asyncio.gather 并发查询提升性能

3. 添加调试日志
   - 记录摄像头查询请求和响应
   - 便于排查问题

测试结果:
- 告警汇总: cam_1f0e3dad9990 → "大堂吧台3" ✓
- 告警列表: cam_1f0e3dad9990 → "大堂吧台3" ✓

相关文件:
- app/routers/yudao_aiot_alarm.py
This commit is contained in:
2026-02-24 13:45:07 +08:00
parent 4eaad734ba
commit ea20175616

View File

@@ -29,7 +29,7 @@ from app.utils.logger import logger
router = APIRouter(prefix="/admin-api/aiot/alarm", tags=["AIoT-告警"])
def _alarm_to_camel(alarm_dict: dict) -> dict:
async def _alarm_to_camel(alarm_dict: dict, current_user: dict = None) -> dict:
"""将 alarm_event 字典转换为前端 camelCase 格式(兼容前端旧字段名)"""
# snapshot_url: 根据存储方式转为可访问 URL
storage = get_oss_storage()
@@ -61,6 +61,27 @@ def _alarm_to_camel(alarm_dict: dict) -> dict:
alarm_id = alarm_dict.get("alarm_id")
# 查询摄像头名称(三级 fallback 策略)
device_id = alarm_dict.get("device_id")
device_name = device_id # 默认使用 device_id
if current_user and device_id:
try:
camera_info = await _get_camera_info(device_id, current_user)
if camera_info:
# 1. 优先使用 gb_name去除 "/" 后缀)
gb_name = camera_info.get("gbName") or camera_info.get("gb_name")
if gb_name:
device_name = gb_name.split("/")[0]
# 2. 其次使用 name 字段
elif camera_info.get("name"):
device_name = camera_info.get("name")
# 3. 最后才使用 app 字段
elif camera_info.get("app"):
device_name = camera_info.get("app")
except Exception as e:
logger.warning(f"告警列表查询摄像头信息失败: device_id={device_id}, error={e}")
return {
# 新字段(三表结构)
"alarmId": alarm_id,
@@ -68,7 +89,7 @@ def _alarm_to_camel(alarm_dict: dict) -> dict:
"alarmTypeName": _get_alarm_type_name(alarm_dict.get("alarm_type")),
"algorithmCode": alarm_dict.get("algorithm_code"),
"deviceId": alarm_dict.get("device_id"),
"deviceName": alarm_dict.get("device_id"),
"deviceName": device_name,
"sceneId": alarm_dict.get("scene_id"),
"eventTime": alarm_dict.get("event_time"),
"firstFrameTime": alarm_dict.get("first_frame_time"),
@@ -140,7 +161,8 @@ async def get_alert_page(
page_size=pageSize,
)
alarm_list = [_alarm_to_camel(a.to_dict()) for a in alarms]
# 并发查询所有告警的摄像头名称
alarm_list = await asyncio.gather(*[_alarm_to_camel(a.to_dict(), current_user) for a in alarms])
return YudaoResponse.page(
list_data=alarm_list,
@@ -165,7 +187,7 @@ async def get_alert(
if not alarm_dict:
raise HTTPException(status_code=404, detail="告警不存在")
return YudaoResponse.success(_alarm_to_camel(alarm_dict))
return YudaoResponse.success(await _alarm_to_camel(alarm_dict, current_user))
@router.put("/alert/handle")
@@ -359,13 +381,6 @@ async def _get_camera_info(device_id: str, current_user: dict) -> Optional[dict]
从 WVP 查询摄像头信息
支持 camera_code 和 app/stream 两种格式
"""
# 获取 token
token = current_user.get("access_token") or current_user.get("token")
if not token:
return None
headers = {"Authorization": f"Bearer {token}"}
# 如果是 camera_code 格式cam_xxxxxxxxxxxx
if device_id.startswith("cam_"):
try:
@@ -375,8 +390,10 @@ async def _get_camera_info(device_id: str, current_user: dict) -> Optional[dict]
f"{WVP_API_BASE}/api/ai/camera/get",
params={"cameraCode": device_id},
)
logger.info(f"查询摄像头: device_id={device_id}, status={resp.status_code}")
if resp.status_code == 200:
data = resp.json()
logger.info(f"WVP 响应: {data}")
if data.get("code") == 0:
return data.get("data")
except Exception as e:
@@ -384,6 +401,13 @@ async def _get_camera_info(device_id: str, current_user: dict) -> Optional[dict]
# 如果是 app/stream 格式
elif "/" in device_id:
# 获取 tokenapp/stream 查询需要认证)
token = current_user.get("access_token") or current_user.get("token")
if not token:
logger.warning(f"查询 app/stream 失败: 缺少 token, device_id={device_id}")
return None
headers = {"Authorization": f"Bearer {token}"}
parts = device_id.split("/", 1)
if len(parts) == 2:
app, stream = parts