修复 Agent 对接 IoT 工单平台:状态同步、图片持久化、roiId 字段

1. agent_dispatcher: IoT 成功与否都更新本地告警状态,不再依赖回调同步
2. agent_dispatcher: submit_order_result 持久化图片 URL 到 alarm_event_ext
3. work_order_client: create_order 添加 roi_id/source_type 参数
4. notify_dispatch: 创建工单时传 scene_id 作为 roiId
This commit is contained in:
2026-03-25 12:37:00 +08:00
parent 7d4c916055
commit eb2d74bd4c
3 changed files with 60 additions and 40 deletions

View File

@@ -557,14 +557,12 @@ class AgentDispatcher:
wo_client = get_work_order_client()
if action == "confirm":
remark = "企微Agent确认接单"
if order_id and wo_client.enabled:
success = await wo_client.confirm_order(order_id)
if not success:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CONFIRMED",
handle_status="HANDLING", handler=user_id, remark="企微Agent确认(IoT降级)")
else:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CONFIRMED",
handle_status="HANDLING", handler=user_id, remark="企微Agent确认接单")
if not await wo_client.confirm_order(order_id):
remark += "(IoT降级)"
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CONFIRMED",
handle_status="HANDLING", handler=user_id, remark=remark)
# 更新卡片到 step2
response_code = wechat.get_response_code(alarm_id)
if response_code:
@@ -575,14 +573,12 @@ class AgentDispatcher:
return {"success": True, "message": f"已确认接单: {alarm_id}"}
elif action == "ignore":
remark = "企微Agent忽略"
if order_id and wo_client.enabled:
success = await wo_client.false_alarm(order_id)
if not success:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="FALSE",
handle_status="IGNORED", handler=user_id, remark="企微Agent忽略(IoT降级)")
else:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="FALSE",
handle_status="IGNORED", handler=user_id, remark="企微Agent忽略")
if not await wo_client.false_alarm(order_id):
remark += "(IoT降级)"
svc.handle_alarm(alarm_id=alarm_id, alarm_status="FALSE",
handle_status="IGNORED", handler=user_id, remark=remark)
response_code = wechat.get_response_code(alarm_id)
if response_code:
await wechat.update_alarm_card_terminal(
@@ -592,14 +588,12 @@ class AgentDispatcher:
return {"success": True, "message": f"已忽略: {alarm_id}"}
elif action == "complete":
remark = "企微Agent已处理"
if order_id and wo_client.enabled:
success = await wo_client.submit_order(order_id, result=f"已处理 by {user_id}")
if not success:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CLOSED",
handle_status="DONE", handler=user_id, remark="企微Agent完成(IoT降级)")
else:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CLOSED",
handle_status="DONE", handler=user_id, remark="企微Agent已处理")
if not await wo_client.submit_order(order_id, result=f"已处理 by {user_id}"):
remark += "(IoT降级)"
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CLOSED",
handle_status="DONE", handler=user_id, remark=remark)
response_code = wechat.get_response_code(alarm_id)
if response_code:
await wechat.update_alarm_card_terminal(
@@ -609,14 +603,12 @@ class AgentDispatcher:
return {"success": True, "message": f"已处理完成: {alarm_id}"}
elif action == "false":
remark = "企微Agent标记误报"
if order_id and wo_client.enabled:
success = await wo_client.false_alarm(order_id)
if not success:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="FALSE",
handle_status="IGNORED", handler=user_id, remark="企微Agent误报(IoT降级)")
else:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="FALSE",
handle_status="IGNORED", handler=user_id, remark="企微Agent标记误报")
if not await wo_client.false_alarm(order_id):
remark += "(IoT降级)"
svc.handle_alarm(alarm_id=alarm_id, alarm_status="FALSE",
handle_status="IGNORED", handler=user_id, remark=remark)
response_code = wechat.get_response_code(alarm_id)
if response_code:
await wechat.update_alarm_card_terminal(
@@ -694,21 +686,40 @@ class AgentDispatcher:
from app.services.work_order_client import get_work_order_client
wo_client = get_work_order_client()
remark = f"企微Agent结单: {result_text}"
if image_urls:
remark += f" (附{len(image_urls)}张图片)"
if order_id and wo_client.enabled:
success = await wo_client.submit_order(
if not await wo_client.submit_order(
order_id,
result=f"{result_text} by {user_id}",
result_img_urls=image_urls or None,
)
if not success:
# IoT 降级
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CLOSED",
handle_status="DONE", handler=user_id,
remark=f"企微Agent结单(IoT降级): {result_text}")
else:
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CLOSED",
handle_status="DONE", handler=user_id,
remark=f"企微Agent结单: {result_text}")
):
remark += "(IoT降级)"
svc.handle_alarm(alarm_id=alarm_id, alarm_status="CLOSED",
handle_status="DONE", handler=user_id, remark=remark)
# 持久化处理结果图片到 alarm_event_ext
if image_urls:
try:
from app.models import get_session as get_db_session, AlarmEventExt
db = get_db_session()
try:
ext = AlarmEventExt(
alarm_id=alarm_id,
ext_type="HANDLER_RESULT",
ext_data={"result_text": result_text, "image_urls": image_urls, "handler": user_id},
)
db.add(ext)
db.commit()
except Exception as e:
db.rollback()
logger.error(f"持久化处理结果图片失败: {e}")
finally:
db.close()
except Exception as e:
logger.error(f"保存处理结果失败: {e}")
# 更新卡片到终态
response_code = wechat.get_response_code(alarm_id)

View File

@@ -182,6 +182,8 @@ async def process_alarm_notification(alarm_data: Dict):
trigger_source=trigger_source,
camera_id=device_id,
image_url=permanent_url,
roi_id=scene_id or "",
source_type="ALARM",
)
if order_id:
_save_order_id(alarm_id, order_id)

View File

@@ -85,6 +85,8 @@ class WorkOrderClient:
trigger_source: str = "自动上报",
camera_id: str = "",
image_url: str = "",
roi_id: str = "",
source_type: str = "",
) -> Optional[str]:
"""
创建安保工单
@@ -123,19 +125,24 @@ class WorkOrderClient:
body["cameraId"] = camera_id
if image_url:
body["imageUrl"] = image_url
if roi_id:
body["roiId"] = roi_id
if source_type:
body["sourceType"] = source_type
body_json = json.dumps(body, ensure_ascii=False, separators=(",", ":"))
try:
headers = self._build_headers(body_json)
url = f"{self._base_url}/open-api/ops/security/order/create"
logger.info(f"创建工单请求: url={url}, body={body_json}")
async with httpx.AsyncClient(timeout=self._timeout) as client:
resp = await client.post(url, content=body_json, headers=headers)
data = resp.json()
if data.get("code") != 0:
logger.error(f"创建工单失败: {data}")
logger.error(f"创建工单失败: status={resp.status_code}, resp={data}, body={body_json}")
return None
# API 返回 {"code":0, "data": 1234567890} — data 直接是 orderId