修复:恢复 send-card 接口,dispatched 只记录日志不发企微

This commit is contained in:
2026-03-27 14:11:03 +08:00
parent 058fc0dbaf
commit 3a62202406

View File

@@ -2,24 +2,38 @@
企微通知 API — 供 IoT 平台调用
IoT 平台通过这些接口驱动企微消息:
- /sync-status: 工单状态变更后同步dispatched发企微、confirmed更新卡片、终态更新告警+卡片
- /send-card: 工单派单后发送企微群聊+私发卡片
- /sync-status: 工单状态变更后同步confirmed更新卡片、终态更新告警+卡片)
"""
import json
from fastapi import APIRouter, Request
from pydantic import BaseModel
from typing import Optional
from typing import List, Optional
from app.utils.logger import logger
router = APIRouter(prefix="/api/wechat/notify", tags=["企微通知-IoT回调"])
class SendCardRequest(BaseModel):
"""IoT 派单后发送企微卡片"""
alarmId: str
orderId: str
userIds: List[str]
title: str
areaName: Optional[str] = ""
cameraName: Optional[str] = ""
eventTime: Optional[str] = ""
level: Optional[int] = 2
snapshotUrl: Optional[str] = ""
class SyncStatusRequest(BaseModel):
"""IoT 工单状态变更后同步"""
alarmId: str
orderId: str
status: str # confirmed / completed / false_alarm / auto_resolved / dispatched
status: str # dispatched / confirmed / completed / false_alarm / auto_resolved
operator: Optional[str] = ""
remark: Optional[str] = ""
@@ -60,88 +74,63 @@ async def _parse_body(request: Request) -> dict:
return {}
async def _send_wechat_on_dispatch(req, wechat):
"""dispatched 时发企微群聊+私发卡片"""
@router.post("/send-card")
async def send_card(request: Request):
"""IoT 派单后调用,发送企微群聊+私发卡片"""
try:
from app.models import get_session, AlarmEvent
from app.services.camera_name_service import get_camera_name_service
from app.services.wechat_service import ALARM_TYPE_NAMES
data = await _parse_body(request)
logger.info(f"IoT send-card 收到数据: {data}")
req = SendCardRequest(**data)
from app.services.wechat_service import get_wechat_service
from app.config import settings
# 查告警信息
db = get_session()
try:
alarm = db.query(AlarmEvent).filter(AlarmEvent.alarm_id == req.alarmId).first()
if not alarm:
logger.warning(f"dispatched 发企微: 告警不存在 {req.alarmId}")
return
alarm_type = alarm.alarm_type or ""
device_id = alarm.device_id or ""
alarm_level = alarm.alarm_level or 2
event_time = alarm.event_time
snapshot_url = alarm.snapshot_url or ""
area_id = alarm.area_id
finally:
db.close()
# 摄像头名称
camera_service = get_camera_name_service()
camera_info = await camera_service.get_camera_info(device_id)
camera_name = camera_service.format_display_name(device_id, camera_info)
# 区域名称
area_name = ""
if area_id:
from app.services.notify_dispatch import _get_area_name_from_iot
area_name = await _get_area_name_from_iot(area_id)
if not area_name:
area_name = "未知区域"
# event_time 格式化
if hasattr(event_time, 'strftime'):
event_time_str = event_time.strftime("%m-%d %H:%M")
else:
s = str(event_time or "")
event_time_str = s[5:16] if len(s) >= 16 else s
# 截图预签名URL
from app.services.notify_dispatch import _get_presigned_url
presigned_url = _get_presigned_url(snapshot_url)
wechat = get_wechat_service()
if not wechat.enabled:
return {"code": -1, "msg": "企微未启用"}
# 群聊通知
group_chat_id = settings.wechat.group_chat_id
if group_chat_id:
# 截图预签名URL
from app.services.notify_dispatch import _get_presigned_url
presigned_url = _get_presigned_url(req.snapshotUrl or "")
await wechat.send_group_alarm_combo(
chat_id=group_chat_id,
alarm_id=req.alarmId,
alarm_type=alarm_type,
area_name=area_name,
camera_name=camera_name,
alarm_type=req.title,
area_name=req.areaName or "",
camera_name=req.cameraName or "",
description=f"工单编号:{req.orderId}",
event_time=event_time_str,
alarm_level=alarm_level,
event_time=req.eventTime or "",
alarm_level=req.level or 2,
snapshot_url=presigned_url,
mention_user_ids=[req.operator] if req.operator else [],
mention_user_ids=req.userIds,
)
# 私发卡片
user_ids = [req.operator] if req.operator else []
if user_ids:
await wechat.send_alarm_card(
user_ids=user_ids,
alarm_id=req.alarmId,
alarm_type=alarm_type,
area_name=area_name,
camera_name=camera_name,
description=f"工单编号:{req.orderId}",
event_time=event_time_str,
alarm_level=alarm_level,
)
sent = await wechat.send_alarm_card(
user_ids=req.userIds,
alarm_id=req.alarmId,
alarm_type=req.title,
area_name=req.areaName or "",
camera_name=req.cameraName or "",
description=f"工单编号:{req.orderId}",
event_time=req.eventTime or "",
alarm_level=req.level or 2,
)
logger.info(f"dispatched 企微通知已发送: alarm={req.alarmId}, order={req.orderId}")
if sent:
logger.info(f"IoT回调发卡片成功: alarm={req.alarmId}, order={req.orderId}, users={req.userIds}")
return {"code": 0, "msg": "success"}
else:
return {"code": -1, "msg": "发送失败"}
except Exception as e:
logger.error(f"dispatched 发企微失败: alarm={req.alarmId}, error={e}", exc_info=True)
logger.error(f"IoT回调发卡片异常: {e}", exc_info=True)
return {"code": -1, "msg": str(e)}
@router.post("/sync-status")
@@ -160,9 +149,8 @@ async def sync_status(request: Request):
wechat = get_wechat_service()
if req.status == "dispatched":
# 派单:发企微群聊+私发卡片(不更新告警)
if wechat.enabled:
await _send_wechat_on_dispatch(req, wechat)
# 派单:不更新告警,不发企微(企微由 send-card 接口发
logger.info(f"dispatched 已记录: alarm={req.alarmId}, order={req.orderId}")
return {"code": 0, "msg": "success"}
elif req.status == "confirmed":