Files
iot-device-management-service/app/services/agent/tools/order_action.py
16337 63a8d5a8f2 告警-工单解耦:企微交互+Agent全面切换到工单驱动
Part A: 数据层
- 新增 WechatCardState 模型(order_id ↔ alarm_id 映射 + response_code)
- 新建 models_iot.py(IoT 工单只读 ORM:ops_order + security_ext + clean_ext)
- config.py 新增 IOT_DATABASE_URL 配置

Part B: 企微解耦(alarm_id → order_id)
- wechat_service: response_code 存储迁移到 wechat_card_state,集中 helper
- 卡片发送/更新方法改用 order_id,按钮 key: confirm_{order_id}
- wechat_callback: 按钮解析改 order_id,反查 alarm_id(可空)
- wechat_notify_api: send-card/sync-status 以 orderId 为主键
- yudao_aiot_alarm: 卡片操作改用 order_id,删重复 helper

Part C: Agent 工具全面改为工单驱动
- 新建 order_query.py(查 IoT ops_order,支持安保+保洁工单)
- 新建 order_action.py(操作工单状态 + 提交处理结果)
- 更新 prompts.py 为工单助手
- 更新工具注册(__init__.py)

Part D: 日报改为工单驱动
- daily_report_service 从查 alarm_event 改为查 IoT ops_order + 扩展表
- 支持安保+保洁工单统计
2026-03-31 10:49:42 +08:00

183 lines
6.5 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.

"""
工单操作工具:确认接单、完成、误报、提交处理结果
"""
import json
from typing import Optional, List
from langchain_core.tools import tool
from langchain_core.runnables import RunnableConfig
from app.utils.logger import logger
async def _update_wechat_card(order_id: str, user_id: str, action: str):
"""更新企微卡片状态(以 order_id 为 key"""
try:
from app.services.wechat_service import get_wechat_service
wechat = get_wechat_service()
response_code = wechat.get_response_code(order_id)
if not response_code:
return
if action == "confirm":
await wechat.update_alarm_card_step2(
response_code=response_code, user_ids=[user_id],
order_id=order_id, operator_name=user_id,
)
else:
await wechat.update_alarm_card_terminal(
response_code=response_code, user_ids=[user_id],
order_id=order_id, action=action, operator_name=user_id,
)
except Exception as e:
logger.error(f"更新企微卡片失败: order={order_id}, error={e}")
@tool
async def update_order_status(order_id: str, action: str, config: RunnableConfig) -> str:
"""更新工单状态:确认接单(confirm)、处理完成(complete)、标记误报(false)、忽略(ignore)
Args:
order_id: 工单IDops_order.id
action: 操作类型 confirm=确认接单 complete=处理完成 false=标记误报 ignore=忽略
"""
user_id = config.get("configurable", {}).get("user_id", "")
from app.services.work_order_client import get_work_order_client
wo_client = get_work_order_client()
if not wo_client.enabled:
return json.dumps({"error": "工单系统未启用"}, ensure_ascii=False)
# IoT 工单操作
iot_success = False
if action == "confirm":
iot_success = await wo_client.confirm_order(order_id)
elif action in ("ignore", "false"):
iot_success = await wo_client.false_alarm(order_id)
elif action == "complete":
iot_success = await wo_client.submit_order(order_id, result=f"已处理 by {user_id}")
if not iot_success:
return json.dumps({"error": f"工单操作失败: order={order_id}, action={action}"}, ensure_ascii=False)
# 有关联告警时同步告警状态
from app.services.wechat_service import get_wechat_service
wechat = get_wechat_service()
alarm_id = wechat.get_alarm_id_for_order(order_id)
if alarm_id:
action_map = {
"confirm": ("CONFIRMED", "HANDLING", "Agent确认接单"),
"ignore": ("FALSE", "IGNORED", "Agent忽略"),
"complete": ("CLOSED", "DONE", "Agent已处理"),
"false": ("FALSE", "IGNORED", "Agent标记误报"),
}
if action in action_map:
alarm_status, handle_status, remark = action_map[action]
from app.services.alarm_event_service import get_alarm_event_service
svc = get_alarm_event_service()
svc.handle_alarm(
alarm_id=alarm_id, alarm_status=alarm_status,
handle_status=handle_status, handler=user_id, remark=remark,
)
# 更新企微卡片
await _update_wechat_card(order_id, user_id, action)
action_labels = {
"confirm": "已确认接单",
"ignore": "已忽略",
"complete": "已处理完成",
"false": "已标记误报",
}
return json.dumps(
{"success": True, "message": f"{action_labels.get(action, action)}: 工单{order_id}"},
ensure_ascii=False,
)
@tool
async def submit_order_result(
order_id: str,
result_text: str,
config: RunnableConfig,
image_urls: Optional[List[str]] = None,
) -> str:
"""提交工单处理结果(文字描述+处理后照片URL
Args:
order_id: 工单IDops_order.id
result_text: 处理结果描述
image_urls: 处理后照片URL列表COS永久URL
"""
user_id = config.get("configurable", {}).get("user_id", "")
if image_urls is None:
image_urls = []
# 合并 session 中暂存的图片
from app.services.session_manager import get_session_manager
session = get_session_manager().get(user_id)
if session.pending_images:
image_urls = session.pending_images + image_urls
session.pending_images = []
from app.services.work_order_client import get_work_order_client
wo_client = get_work_order_client()
if wo_client.enabled:
success = await wo_client.submit_order(
order_id,
result=f"{result_text} by {user_id}",
result_img_urls=image_urls or None,
)
if not success:
return json.dumps({"error": f"提交工单结果失败: order={order_id}"}, ensure_ascii=False)
# 有关联告警时同步告警状态
from app.services.wechat_service import get_wechat_service
wechat = get_wechat_service()
alarm_id = wechat.get_alarm_id_for_order(order_id)
if alarm_id:
from app.services.alarm_event_service import get_alarm_event_service
svc = get_alarm_event_service()
remark = f"Agent结单: {result_text}"
if image_urls:
remark += f" (附{len(image_urls)}张图片)"
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}")
# 更新卡片到终态
await _update_wechat_card(order_id, user_id, "complete")
result = {
"success": True,
"message": f"工单已提交: {order_id}",
"result": result_text,
"images_count": len(image_urls),
}
return json.dumps(result, ensure_ascii=False)