diff --git a/app/main.py b/app/main.py index ce02c8f..eeeab82 100644 --- a/app/main.py +++ b/app/main.py @@ -111,6 +111,11 @@ _uploads_dir = Path("uploads") _uploads_dir.mkdir(parents=True, exist_ok=True) app.mount("/uploads", StaticFiles(directory=str(_uploads_dir)), name="uploads") +# H5 告警详情页面(企微卡片"查看详情"跳转目标) +_static_dir = Path(__file__).parent / "static" +if _static_dir.exists(): + app.mount("/static", StaticFiles(directory=str(_static_dir)), name="static") + def get_alert_svc(): return alert_service diff --git a/app/routers/wechat_callback.py b/app/routers/wechat_callback.py index 7794ffe..f62107f 100644 --- a/app/routers/wechat_callback.py +++ b/app/routers/wechat_callback.py @@ -1,15 +1,17 @@ """ 企微回调路由 -处理安保人员在企微卡片上的操作(确认处理/已处理完成/误报忽略)。 +处理安保人员在企微卡片上的操作(前往处理/已处理/误报忽略)。 +提供告警详情接口供 H5 页面使用。 """ from datetime import datetime -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, Query from pydantic import BaseModel from typing import Optional from app.yudao_compat import YudaoResponse +from app.models import get_session, AlarmEvent, AlarmLlmAnalysis from app.services.alarm_event_service import get_alarm_event_service, AlarmEventService from app.utils.logger import logger @@ -24,16 +26,55 @@ class AlarmActionRequest(BaseModel): remark: Optional[str] = None +@router.get("/alarm_detail") +async def get_alarm_detail(alarm_id: str = Query(..., description="告警ID")): + """ + 告警详情接口(供 H5 页面使用,无认证) + + 返回告警基本信息 + VLM 分析描述 + """ + db = get_session() + try: + alarm = db.query(AlarmEvent).filter(AlarmEvent.alarm_id == alarm_id).first() + if not alarm: + return YudaoResponse.error(404, "告警不存在") + + # 查 VLM 分析结果 + vlm_desc = "" + analysis = db.query(AlarmLlmAnalysis).filter( + AlarmLlmAnalysis.alarm_id == alarm_id + ).order_by(AlarmLlmAnalysis.id.desc()).first() + if analysis: + vlm_desc = analysis.summary or "" + + return YudaoResponse.success({ + "alarm_id": alarm.alarm_id, + "alarm_type": alarm.alarm_type, + "device_id": alarm.device_id, + "scene_id": alarm.scene_id, + "event_time": alarm.event_time.strftime('%Y-%m-%d %H:%M:%S') if alarm.event_time else "", + "alarm_level": alarm.alarm_level, + "alarm_status": alarm.alarm_status, + "handle_status": alarm.handle_status, + "snapshot_url": alarm.snapshot_url or "", + "handler": alarm.handler or "", + "handle_remark": alarm.handle_remark or "", + "vlm_description": vlm_desc, + }) + finally: + db.close() + + @router.post("/callback/alarm_action") async def alarm_action_callback( req: AlarmActionRequest, service: AlarmEventService = Depends(get_alarm_event_service), ): """ - 企微告警操作回调(无认证,由企微服务端调用) + 企微告警操作回调(无认证,由 H5 页面调用) action: - - confirm: 确认处理 → handle_status=HANDLING + - confirm: 前往处理 → handle_status=HANDLING - complete: 已处理完成 → handle_status=DONE, alarm_status=CLOSED - ignore: 误报忽略 → alarm_status=FALSE, handle_status=DONE """ @@ -41,17 +82,17 @@ async def alarm_action_callback( "confirm": { "alarm_status": "CONFIRMED", "handle_status": "HANDLING", - "remark": "企微确认处理", + "remark": "前往处理", }, "complete": { "alarm_status": "CLOSED", "handle_status": "DONE", - "remark": "企微手动结单", + "remark": "手动结单", }, "ignore": { "alarm_status": "FALSE", "handle_status": "DONE", - "remark": "企微标记误报", + "remark": "标记误报", }, } diff --git a/app/services/notify_dispatch.py b/app/services/notify_dispatch.py index 55c087b..71d09af 100644 --- a/app/services/notify_dispatch.py +++ b/app/services/notify_dispatch.py @@ -19,6 +19,7 @@ from app.models import ( AlarmEvent, AlarmLlmAnalysis, CameraAreaBinding, AreaPersonBinding, NotifyArea, ) +from app.config import settings from app.services.vlm_service import get_vlm_service from app.services.wechat_service import get_wechat_service @@ -94,6 +95,7 @@ async def process_alarm_notification(alarm_data: Dict): snapshot_url=snapshot_url, event_time=event_time_str, alarm_level=alarm_level, + service_base_url=f"http://{settings.app.host}:{settings.app.port}", ) logger.info(f"告警通知完成: {alarm_id} → {len(persons)} 人") diff --git a/app/services/wechat_service.py b/app/services/wechat_service.py index a4b0838..6a612a3 100644 --- a/app/services/wechat_service.py +++ b/app/services/wechat_service.py @@ -75,6 +75,7 @@ class WeChatService: snapshot_url: str, event_time: str, alarm_level: int = 2, + service_base_url: str = "", ) -> bool: """ 发送告警文本卡片 @@ -120,6 +121,9 @@ class WeChatService: f"