267 lines
9.6 KiB
Python
267 lines
9.6 KiB
Python
import json
|
||
from datetime import date
|
||
|
||
from fastapi import APIRouter, Query, HTTPException, Path
|
||
from mysql.connector import Error as MySQLError
|
||
|
||
from ds.db import db
|
||
from encryption.encrypt_decorator import encrypt_response
|
||
from schema.device_danger_schema import (
|
||
DeviceDangerCreateRequest, DeviceDangerResponse, DeviceDangerListResponse
|
||
)
|
||
from schema.response_schema import APIResponse
|
||
|
||
# 路由初始化(前缀与设备管理相关,标签区分功能)
|
||
router = APIRouter(
|
||
prefix="/api/devices/dangers",
|
||
tags=["设备管理-危险记录"]
|
||
)
|
||
|
||
|
||
# ------------------------------
|
||
# 内部工具方法 - 检查设备是否存在(复用设备表逻辑)
|
||
# ------------------------------
|
||
def check_device_exist(client_ip: str) -> bool:
|
||
"""
|
||
检查指定IP的设备是否在devices表中存在
|
||
|
||
:param client_ip: 设备IP地址
|
||
:return: 存在返回True,不存在返回False
|
||
"""
|
||
if not client_ip:
|
||
raise ValueError("设备IP不能为空")
|
||
|
||
conn = None
|
||
cursor = None
|
||
try:
|
||
conn = db.get_connection()
|
||
cursor = conn.cursor(dictionary=True)
|
||
|
||
cursor.execute("SELECT id FROM devices WHERE client_ip = %s", (client_ip,))
|
||
return cursor.fetchone() is not None
|
||
except MySQLError as e:
|
||
raise Exception(f"检查设备存在性失败: {str(e)}") from e
|
||
finally:
|
||
db.close_connection(conn, cursor)
|
||
|
||
|
||
# ------------------------------
|
||
# 内部工具方法 - 创建设备危险记录(核心插入逻辑)
|
||
# ------------------------------
|
||
def create_danger_record(danger_data: DeviceDangerCreateRequest) -> DeviceDangerResponse:
|
||
"""
|
||
内部工具方法:向device_danger表插入新的危险记录
|
||
|
||
:param danger_data: 危险记录创建请求数据
|
||
:return: 创建成功的危险记录模型对象
|
||
"""
|
||
# 先检查设备是否存在
|
||
if not check_device_exist(danger_data.client_ip):
|
||
raise ValueError(f"IP为 {danger_data.client_ip} 的设备不存在,无法创建危险记录")
|
||
|
||
conn = None
|
||
cursor = None
|
||
try:
|
||
conn = db.get_connection()
|
||
cursor = conn.cursor(dictionary=True)
|
||
|
||
# 插入危险记录(id自增,时间自动填充)
|
||
insert_query = """
|
||
INSERT INTO device_danger
|
||
(client_ip, type, result, created_at, updated_at)
|
||
VALUES (%s, %s, %s, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||
"""
|
||
cursor.execute(insert_query, (
|
||
danger_data.client_ip,
|
||
danger_data.type,
|
||
danger_data.result
|
||
))
|
||
conn.commit()
|
||
|
||
# 获取刚创建的记录(用自增ID查询)
|
||
danger_id = cursor.lastrowid
|
||
cursor.execute("SELECT * FROM device_danger WHERE id = %s", (danger_id,))
|
||
new_danger = cursor.fetchone()
|
||
|
||
return DeviceDangerResponse(**new_danger)
|
||
except MySQLError as e:
|
||
if conn:
|
||
conn.rollback()
|
||
raise Exception(f"插入危险记录失败: {str(e)}") from e
|
||
finally:
|
||
db.close_connection(conn, cursor)
|
||
|
||
|
||
# ------------------------------
|
||
# 接口1:创建设备危险记录
|
||
# ------------------------------
|
||
@router.post("/add", response_model=APIResponse, summary="创建设备危险记录")
|
||
@encrypt_response()
|
||
async def add_device_danger(danger_data: DeviceDangerCreateRequest):
|
||
try:
|
||
# 调用内部方法创建记录
|
||
new_danger = create_danger_record(danger_data)
|
||
|
||
return APIResponse(
|
||
code=200,
|
||
message=f"设备[{danger_data.client_ip}]危险记录创建成功",
|
||
data=new_danger
|
||
)
|
||
except ValueError as e:
|
||
# 设备不存在等业务异常
|
||
raise HTTPException(status_code=400, detail=str(e)) from e
|
||
except Exception as e:
|
||
# 数据库异常等系统错误
|
||
raise HTTPException(status_code=500, detail=str(e)) from e
|
||
|
||
|
||
# ------------------------------
|
||
# 接口2:获取危险记录列表(支持多条件筛选+分页)
|
||
# ------------------------------
|
||
@router.get("/", response_model=APIResponse, summary="获取设备危险记录列表(多条件筛选)")
|
||
@encrypt_response()
|
||
async def get_danger_list(
|
||
page: int = Query(1, ge=1, description="页码,默认第1页"),
|
||
page_size: int = Query(10, ge=1, le=100, description="每页条数,1-100之间"),
|
||
client_ip: str = Query(None, max_length=100, description="按设备IP筛选"),
|
||
danger_type: str = Query(None, max_length=50, alias="type", description="按危险类型筛选"),
|
||
start_date: date = Query(None, description="按创建时间筛选(开始日期,格式YYYY-MM-DD)"),
|
||
end_date: date = Query(None, description="按创建时间筛选(结束日期,格式YYYY-MM-DD)")
|
||
):
|
||
conn = None
|
||
cursor = None
|
||
try:
|
||
conn = db.get_connection()
|
||
cursor = conn.cursor(dictionary=True)
|
||
|
||
# 构建筛选条件
|
||
where_clause = []
|
||
params = []
|
||
|
||
if client_ip:
|
||
where_clause.append("client_ip = %s")
|
||
params.append(client_ip)
|
||
if danger_type:
|
||
where_clause.append("type = %s")
|
||
params.append(danger_type)
|
||
if start_date:
|
||
where_clause.append("DATE(created_at) >= %s")
|
||
params.append(start_date.strftime("%Y-%m-%d"))
|
||
if end_date:
|
||
where_clause.append("DATE(created_at) <= %s")
|
||
params.append(end_date.strftime("%Y-%m-%d"))
|
||
|
||
# 1. 统计符合条件的总记录数
|
||
count_query = "SELECT COUNT(*) AS total FROM device_danger"
|
||
if where_clause:
|
||
count_query += " WHERE " + " AND ".join(where_clause)
|
||
cursor.execute(count_query, params)
|
||
total = cursor.fetchone()["total"]
|
||
|
||
# 2. 分页查询记录(按创建时间倒序,最新的在前)
|
||
offset = (page - 1) * page_size
|
||
list_query = "SELECT * FROM device_danger"
|
||
if where_clause:
|
||
list_query += " WHERE " + " AND ".join(where_clause)
|
||
list_query += " ORDER BY created_at DESC LIMIT %s OFFSET %s"
|
||
params.extend([page_size, offset]) # 追加分页参数
|
||
|
||
cursor.execute(list_query, params)
|
||
danger_list = cursor.fetchall()
|
||
|
||
# 转换为响应模型
|
||
return APIResponse(
|
||
code=200,
|
||
message="获取危险记录列表成功",
|
||
data=DeviceDangerListResponse(
|
||
total=total,
|
||
dangers=[DeviceDangerResponse(**item) for item in danger_list]
|
||
)
|
||
)
|
||
except MySQLError as e:
|
||
raise HTTPException(status_code=500, detail=f"查询危险记录失败: {str(e)}") from e
|
||
finally:
|
||
db.close_connection(conn, cursor)
|
||
|
||
|
||
# ------------------------------
|
||
# 接口3:获取单个设备的所有危险记录
|
||
# ------------------------------
|
||
@router.get("/device/{client_ip}", response_model=APIResponse, summary="获取单个设备的所有危险记录")
|
||
# @encrypt_response()
|
||
async def get_device_dangers(
|
||
client_ip: str = Path(..., max_length=100, description="设备IP地址"),
|
||
page: int = Query(1, ge=1, description="页码,默认第1页"),
|
||
page_size: int = Query(10, ge=1, le=100, description="每页条数,1-100之间")
|
||
):
|
||
# 先检查设备是否存在
|
||
if not check_device_exist(client_ip):
|
||
raise HTTPException(status_code=404, detail=f"IP为 {client_ip} 的设备不存在")
|
||
|
||
conn = None
|
||
cursor = None
|
||
try:
|
||
conn = db.get_connection()
|
||
cursor = conn.cursor(dictionary=True)
|
||
|
||
# 1. 统计该设备的危险记录总数
|
||
count_query = "SELECT COUNT(*) AS total FROM device_danger WHERE client_ip = %s"
|
||
cursor.execute(count_query, (client_ip,))
|
||
total = cursor.fetchone()["total"]
|
||
|
||
# 2. 分页查询该设备的危险记录
|
||
offset = (page - 1) * page_size
|
||
list_query = """
|
||
SELECT * FROM device_danger
|
||
WHERE client_ip = %s
|
||
ORDER BY created_at DESC
|
||
LIMIT %s OFFSET %s
|
||
"""
|
||
cursor.execute(list_query, (client_ip, page_size, offset))
|
||
danger_list = cursor.fetchall()
|
||
|
||
return APIResponse(
|
||
code=200,
|
||
message=f"获取设备[{client_ip}]危险记录成功(共{total}条)",
|
||
data=DeviceDangerListResponse(
|
||
total=total,
|
||
dangers=[DeviceDangerResponse(**item) for item in danger_list]
|
||
)
|
||
)
|
||
except MySQLError as e:
|
||
raise HTTPException(status_code=500, detail=f"查询设备[{client_ip}]危险记录失败: {str(e)}") from e
|
||
finally:
|
||
db.close_connection(conn, cursor)
|
||
|
||
|
||
# ------------------------------
|
||
# 接口4:根据ID获取单个危险记录详情
|
||
# ------------------------------
|
||
@router.get("/{danger_id}", response_model=APIResponse, summary="根据ID获取单个危险记录详情")
|
||
@encrypt_response()
|
||
async def get_danger_detail(
|
||
danger_id: int = Path(..., ge=1, description="危险记录ID")
|
||
):
|
||
conn = None
|
||
cursor = None
|
||
try:
|
||
conn = db.get_connection()
|
||
cursor = conn.cursor(dictionary=True)
|
||
|
||
# 查询单个危险记录
|
||
query = "SELECT * FROM device_danger WHERE id = %s"
|
||
cursor.execute(query, (danger_id,))
|
||
danger = cursor.fetchone()
|
||
|
||
if not danger:
|
||
raise HTTPException(status_code=404, detail=f"ID为 {danger_id} 的危险记录不存在")
|
||
|
||
return APIResponse(
|
||
code=200,
|
||
message="获取危险记录详情成功",
|
||
data=DeviceDangerResponse(**danger)
|
||
)
|
||
except MySQLError as e:
|
||
raise HTTPException(status_code=500, detail=f"查询危险记录详情失败: {str(e)}") from e
|
||
finally:
|
||
db.close_connection(conn, cursor) |