Files
iot-device-management-service/app/routers/wechat_notify_api.py
16337 96856574ca 功能:新增 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 四种状态
2026-03-23 11:51:16 +08:00

136 lines
4.9 KiB
Python
Raw 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.

"""
企微通知 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)}