""" 工单创建测试 — 使用真实告警数据 + 真实截图 1. 从 MySQL 查询最近一条带截图的告警 2. 用该告警数据创建工单到 192.168.0.104:48080 """ import asyncio import hashlib import json import time import uuid import httpx import pymysql from app.constants import ALARM_TYPE_NAMES, ALARM_LEVEL_NAMES # ===== 数据库配置 ===== DB_CONFIG = { "host": "124.221.55.225", "port": 3306, "user": "vsp_user", "password": "VspPass2024!", "database": "aiot_alarm", "charset": "utf8mb4", } # ===== 工单 API 配置 ===== BASE_URL = "http://192.168.0.104:48080" APP_ID = "alarm-system" APP_SECRET = "tQ3v5q1z2ZLu7hrU1yseaHwg1wJUcmF1" TENANT_ID = "1" def query_recent_alarm_with_snapshot(): """从数据库查询最近一条带截图的告警""" conn = pymysql.connect(**DB_CONFIG) try: with conn.cursor(pymysql.cursors.DictCursor) as cur: sql = """ SELECT alarm_id, alarm_type, device_id, scene_id, event_time, alarm_level, confidence_score, snapshot_url, edge_node_id, area_id FROM alarm_event WHERE snapshot_url IS NOT NULL AND snapshot_url != '' ORDER BY event_time DESC LIMIT 5 """ cur.execute(sql) rows = cur.fetchall() return rows finally: conn.close() def build_sign(query_str: str, body_json: str, nonce: str, timestamp: str) -> str: """构建 SHA256 签名""" header_str = f"appId={APP_ID}&nonce={nonce}×tamp={timestamp}" sign_string = f"{query_str}{body_json}{header_str}{APP_SECRET}" return hashlib.sha256(sign_string.encode("utf-8")).hexdigest() def build_headers(body_json: str) -> dict: """构造完整请求头""" nonce = uuid.uuid4().hex[:16] timestamp = str(int(time.time() * 1000)) sign = build_sign("", body_json, nonce, timestamp) return { "Content-Type": "application/json", "tenant-id": TENANT_ID, "appId": APP_ID, "timestamp": timestamp, "nonce": nonce, "sign": sign, } async def create_order(alarm: dict) -> str: """用真实告警数据创建工单""" alarm_type = alarm["alarm_type"] alarm_level = alarm.get("alarm_level", 2) type_name = ALARM_TYPE_NAMES.get(alarm_type, alarm_type) level_name = ALARM_LEVEL_NAMES.get(alarm_level, "一般") device_id = alarm["device_id"] event_time = str(alarm["event_time"])[:19] if alarm["event_time"] else "" body = { "title": f"【{level_name}】{type_name}告警 - {device_id}", "areaId": alarm.get("area_id") or 1317, "alarmId": alarm["alarm_id"], "alarmType": alarm_type, "description": f"设备 {device_id} 于 {event_time} 检测到{type_name},置信度 {alarm.get('confidence_score', 0):.2f}", "priority": alarm_level, "triggerSource": "自动上报", "cameraId": device_id, "imageUrl": alarm["snapshot_url"], } body_json = json.dumps(body, ensure_ascii=False, separators=(",", ":")) headers = build_headers(body_json) url = f"{BASE_URL}/open-api/ops/security/order/create" print(f"\n{'='*60}") print(f"创建工单 — 使用真实告警数据") print(f"{'='*60}") print(f" 告警ID: {alarm['alarm_id']}") print(f" 告警类型: {type_name}") print(f" 设备ID: {device_id}") print(f" 事件时间: {event_time}") print(f" 置信度: {alarm.get('confidence_score', 'N/A')}") print(f" 截图URL: {alarm['snapshot_url'][:80]}...") print(f" 区域ID: {body['areaId']}") print(f" 工单标题: {body['title']}") print() print(f" 请求URL: {url}") print(f" 请求Body: {body_json[:200]}...") print() async with httpx.AsyncClient(timeout=15) as client: resp = await client.post(url, content=body_json, headers=headers) print(f" HTTP Status: {resp.status_code}") print(f" Response Body: {resp.text[:500]}") if resp.status_code == 200: data = resp.json() if data.get("code") == 0: order_id = str(data.get("data", "")) print(f"\n ✅ 工单创建成功! orderId = {order_id}") return order_id else: print(f"\n ❌ API 返回错误: code={data.get('code')}, msg={data.get('msg')}") else: print(f"\n ❌ HTTP 请求失败: {resp.status_code}") return "" async def main(): print(f"工单系统地址: {BASE_URL}") print(f"数据库: {DB_CONFIG['host']}:{DB_CONFIG['port']}/{DB_CONFIG['database']}") print() # 1. 查询最近带截图的告警 print("正在查询最近带截图的告警...") alarms = query_recent_alarm_with_snapshot() if not alarms: print("❌ 未找到带截图的告警,无法测试") return print(f"\n找到 {len(alarms)} 条带截图的告警:") print(f"{'─'*80}") for i, a in enumerate(alarms): type_name = ALARM_TYPE_NAMES.get(a["alarm_type"], a["alarm_type"]) print(f" [{i+1}] {a['alarm_id'][:40]}...") print(f" 类型={type_name} 设备={a['device_id']} 时间={str(a['event_time'])[:19]}") print(f" 截图={a['snapshot_url'][:70]}...") print() # 2. 用第一条创建工单 alarm = alarms[0] print(f"将使用第 1 条告警创建工单...") order_id = await create_order(alarm) if order_id: print(f"\n{'='*60}") print(f"测试完成 — 工单 {order_id} 已创建") print(f"请在 AIoT 平台确认工单内容和截图是否正确") print(f"{'='*60}") if __name__ == "__main__": asyncio.run(main())