功能:新增 IoT 回调接口 send-card 和 sync-status

- POST /api/wechat/notify/send-card — IoT 派单后发企微卡片
- POST /api/wechat/notify/sync-status — IoT 状态变更后同步告警+卡片
- 支持 confirmed/completed/false_alarm/auto_resolved 四种状态
This commit is contained in:
2026-03-23 11:51:16 +08:00
parent bbcd2e5bbe
commit 96856574ca
2 changed files with 137 additions and 0 deletions

View File

@@ -30,6 +30,7 @@ from app.utils.logger import logger
from app.routers import yudao_alert_router, yudao_auth_router, yudao_aiot_alarm_router, yudao_aiot_edge_router, yudao_aiot_storage_router, edge_compat_router
from app.routers.wechat_callback import router as wechat_callback_router
from app.routers.notify_manage import router as notify_manage_router
from app.routers.wechat_notify_api import router as wechat_notify_router
from app.yudao_compat import yudao_exception_handler
import json
@@ -111,6 +112,7 @@ app.include_router(edge_compat_router)
# ==================== 企微回调 + 通知管理路由 ====================
app.include_router(wechat_callback_router)
app.include_router(wechat_notify_router)
app.include_router(notify_manage_router)
# 注册芋道格式异常处理器

View File

@@ -0,0 +1,135 @@
"""
企微通知 API — 供 IoT 平台调用
IoT 平台通过这两个接口驱动企微消息:
- /send-card: 工单派单后发送企微卡片
- /sync-status: 工单状态变更后同步告警状态+更新卡片
"""
from fastapi import APIRouter, Request
from pydantic import BaseModel
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: str = ""
cameraName: str = ""
eventTime: str = ""
level: int = 2
snapshotUrl: str = ""
class SyncStatusRequest(BaseModel):
"""IoT 工单状态变更后同步"""
alarmId: str
orderId: str
status: str # confirmed / completed / false_alarm / auto_resolved
operator: str = ""
remark: str = ""
@router.post("/send-card")
async def send_card(req: SendCardRequest):
"""IoT 派单后调用,发送企微工单卡片给指定保安"""
try:
from app.services.wechat_service import get_wechat_service, ALARM_LEVEL_NAMES
wechat = get_wechat_service()
if not wechat.enabled:
return {"code": -1, "msg": "企微未启用"}
level_name = ALARM_LEVEL_NAMES.get(req.level, "普通")
sent = await wechat.send_alarm_card(
user_ids=req.userIds,
alarm_id=req.alarmId,
alarm_type=req.title,
area_name=req.areaName,
camera_name=req.cameraName,
description=f"工单编号:{req.orderId}",
event_time=req.eventTime,
alarm_level=req.level,
)
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"IoT回调发卡片异常: {e}", exc_info=True)
return {"code": -1, "msg": str(e)}
@router.post("/sync-status")
async def sync_status(req: SyncStatusRequest):
"""IoT 工单状态变更后调用,同步更新告警状态+企微卡片"""
try:
from app.services.alarm_event_service import get_alarm_event_service
from app.services.wechat_service import get_wechat_service
service = get_alarm_event_service()
wechat = get_wechat_service()
# 状态映射
status_map = {
"confirmed": {"alarm_status": "CONFIRMED", "handle_status": "HANDLING", "card_action": None},
"completed": {"alarm_status": "CLOSED", "handle_status": "DONE", "card_action": "complete"},
"false_alarm": {"alarm_status": "FALSE", "handle_status": "IGNORED", "card_action": "false"},
"auto_resolved": {"alarm_status": "CLOSED", "handle_status": "DONE", "card_action": "auto_resolve"},
}
mapping = status_map.get(req.status)
if not mapping:
return {"code": 400, "msg": f"未知状态: {req.status}"}
# 1. 更新告警状态
service.handle_alarm(
alarm_id=req.alarmId,
alarm_status=mapping["alarm_status"],
handle_status=mapping["handle_status"],
handler=req.operator,
remark=req.remark or f"IoT工单同步: {req.status}",
)
logger.info(f"告警状态已同步: alarm={req.alarmId}, status={req.status}")
# 2. 更新企微卡片
if mapping["card_action"] and wechat.enabled:
response_code = wechat.get_response_code(req.alarmId)
if response_code:
if req.status == "confirmed":
# 确认接单重绘卡片提示去H5处理
await wechat.update_alarm_card_step2(
response_code=response_code,
user_ids=[req.operator] if req.operator else [],
alarm_id=req.alarmId,
operator_name=req.operator,
)
else:
# 终态:按钮变灰
await wechat.update_alarm_card_terminal(
response_code=response_code,
user_ids=[req.operator] if req.operator else [],
alarm_id=req.alarmId,
action=mapping["card_action"],
operator_name=req.operator,
)
logger.info(f"卡片已更新: alarm={req.alarmId}, action={mapping['card_action']}")
else:
logger.warning(f"未找到 response_code跳过卡片更新: alarm={req.alarmId}")
return {"code": 0, "msg": "success"}
except Exception as e:
logger.error(f"IoT回调同步状态异常: {e}", exc_info=True)
return {"code": -1, "msg": str(e)}