638 lines
21 KiB
Python
638 lines
21 KiB
Python
|
||
from typing import List, Optional, Dict, Any
|
||
from sqlalchemy import select, and_, or_, update, bindparam, func
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
from sqlalchemy.orm import selectinload
|
||
from app.crud.base import CRUDBase
|
||
from app.models.models import Event, Image, RobotInfo, Temperature, Message, Robot, Task
|
||
from app.schemas.event import AllMessageDto, EventUpdate, EventQuery, BackStageEvent, BackStageEventDto, BackStageEventDetail, EditTemperatureDto, OcrAlertMessage, OcrAlertMessageDto, GetRobotDto, CommonAlertMessage, GetAllMessageDto, TaskListDto
|
||
|
||
from pydantic import VERSION as PYDANTIC_VERSION
|
||
from datetime import datetime, timedelta, timezone
|
||
|
||
# from app.util import kangda
|
||
|
||
class CRUDEvent(CRUDBase[Event, EventUpdate, EventUpdate]):
|
||
async def get_by_id(self, db: AsyncSession, *, event_id: str) -> Optional[Event]:
|
||
"""根据ID获取事件"""
|
||
query = (
|
||
select(Event)
|
||
.options(
|
||
selectinload(Event.images),
|
||
selectinload(Event.temperatures)
|
||
)
|
||
.where(Event.eventId == event_id)
|
||
)
|
||
result = await db.execute(query)
|
||
return result.scalar_one_or_none()
|
||
|
||
async def get_event_detail(
|
||
self,
|
||
db: AsyncSession,
|
||
*,
|
||
eventId: str
|
||
) -> Optional[BackStageEventDetail]:
|
||
stmt = (select(Event.eventId, Event.number, Event.name,Image.imageUrl, Image.localPath, Temperature.temperature,Temperature.confidence, Temperature.status, Temperature.createTime).
|
||
select_from(Event).
|
||
outerjoin(Image, Image.eventId == Event.eventId).
|
||
outerjoin(Temperature, Event.eventId==Temperature.eventId).
|
||
where(Event.eventId==eventId)
|
||
)
|
||
|
||
result = await db.execute(stmt)
|
||
result = result.mappings().first()
|
||
|
||
return result
|
||
|
||
async def get_ocr_result(
|
||
self,
|
||
db: AsyncSession,
|
||
) -> List[BackStageEvent]:
|
||
"""获取所有仪表识别结果"""
|
||
stmt = (
|
||
select(Event.eventId, Event.number, Event.name, Image.imageUrl, Image.localPath, Temperature.temperature, Temperature.confidence, Temperature.createTime, Temperature.status)
|
||
.select_from(Temperature)
|
||
.outerjoin(Event, Event.eventId==Temperature.eventId)
|
||
.outerjoin(Image, Image.imageId == Temperature.imageId)
|
||
.order_by(Temperature.createTime.desc())
|
||
)
|
||
|
||
results = await db.execute(stmt)
|
||
|
||
results = results.mappings().all()
|
||
|
||
back = list()
|
||
|
||
for result in results:
|
||
back.append(BackStageEvent(**result))
|
||
|
||
return back
|
||
|
||
|
||
async def get_multi_backstage_events(
|
||
self,
|
||
db: AsyncSession,
|
||
*,
|
||
query: BackStageEventDto
|
||
) -> List[BackStageEvent]:
|
||
|
||
"""后台根据条件获取事件列表"""
|
||
|
||
conditions = []
|
||
|
||
if query.eventId is not None and len(query.eventId) > 0:
|
||
conditions.append(Event.eventId==query.eventId)
|
||
if query.number is not None and len(query.number) > 0:
|
||
conditions.append(Event.number == query.number)
|
||
if query.name is not None and len(query.name) > 0:
|
||
conditions.append(Event.name == query.name)
|
||
if query.status is not None and len(query.status) > 0:
|
||
conditions.append(Temperature.status == query.status)
|
||
if query.start_time is not None:
|
||
conditions.append(Temperature.createTime >= query.start_time)
|
||
if query.end_time is not None:
|
||
conditions.append(Temperature.createTime <= query.end_time)
|
||
|
||
|
||
|
||
stmt = (
|
||
select(Event.eventId, Event.number, Event.name, Image.imageUrl, Image.localPath, Temperature.temperature, Temperature.confidence, Temperature.createTime, Temperature.status)
|
||
.select_from(Temperature)
|
||
.outerjoin(Event, Event.eventId==Temperature.eventId)
|
||
.outerjoin(Image, Image.imageId == Temperature.imageId)
|
||
.where(*conditions)
|
||
.order_by(Temperature.createTime.desc())
|
||
.offset(query.skip)
|
||
.limit(query.limit)
|
||
)
|
||
|
||
results = await db.execute(stmt)
|
||
|
||
results = results.mappings().all()
|
||
|
||
back = list()
|
||
|
||
for result in results:
|
||
# if result["temperature"] is not None:
|
||
back.append(BackStageEvent(**result))
|
||
|
||
return back
|
||
|
||
|
||
|
||
|
||
async def get_multi_with_query(
|
||
self,
|
||
db: AsyncSession,
|
||
*,
|
||
query: EventQuery
|
||
) -> List[Event]:
|
||
"""根据查询条件获取事件列表"""
|
||
conditions = []
|
||
|
||
if query.start_time:
|
||
conditions.append(Event.insDate >= query.start_time)
|
||
if query.end_time:
|
||
conditions.append(Event.insDate <= query.end_time)
|
||
if query.etypeName:
|
||
conditions.append(Event.etypeName == query.etypeName)
|
||
if query.area:
|
||
conditions.append(Event.area == query.area)
|
||
|
||
query_stmt = (
|
||
select(Event)
|
||
.options(
|
||
selectinload(Event.images),
|
||
selectinload(Event.temperatures)
|
||
)
|
||
)
|
||
|
||
if conditions:
|
||
query_stmt = query_stmt.where(and_(*conditions))
|
||
|
||
query_stmt = query_stmt.offset(query.skip).limit(query.limit)
|
||
|
||
result = await db.execute(query_stmt)
|
||
return result.scalars().all()
|
||
|
||
async def update_event(
|
||
self,
|
||
db: AsyncSession,
|
||
*,
|
||
event_id: str,
|
||
obj_in: EditTemperatureDto
|
||
) -> Optional[Event]:
|
||
"""更新事件信息"""
|
||
|
||
dict_values = dict()
|
||
|
||
if PYDANTIC_VERSION.startswith("2."):
|
||
field_names = list(EditTemperatureDto.model_fields.keys())
|
||
else:
|
||
field_names = list(EditTemperatureDto.__fields__.keys())
|
||
|
||
for key in field_names:
|
||
|
||
value = getattr(obj_in, key)
|
||
if value is not None:
|
||
dict_values[key] = value
|
||
try:
|
||
update_stmt = (
|
||
update(Temperature).where(Temperature.eventId == event_id).values(**dict_values)
|
||
)
|
||
|
||
await db.execute(update_stmt)
|
||
await db.commit()
|
||
|
||
return True
|
||
except:
|
||
return False
|
||
|
||
|
||
# event = await self.get_by_id(db, event_id=event_id)
|
||
# if not event:
|
||
# return None
|
||
|
||
# update_data = obj_in.model_dump()
|
||
# for field, value in update_data.items():
|
||
# setattr(event, field, value)
|
||
|
||
# # db.add(event)
|
||
# await db.commit()
|
||
# await db.refresh(event)
|
||
# return event
|
||
|
||
async def delete_event(
|
||
self,
|
||
db: AsyncSession,
|
||
*,
|
||
event_id: str
|
||
) -> Optional[Event]:
|
||
"""删除事件"""
|
||
event = await self.get_by_id(db, event_id=event_id)
|
||
if not event:
|
||
return None
|
||
|
||
await db.delete(event)
|
||
await db.commit()
|
||
return event
|
||
|
||
async def get_messages(
|
||
self,
|
||
db: AsyncSession,
|
||
skip:int,
|
||
limit:int,
|
||
condition: list = []
|
||
) -> Optional[List[OcrAlertMessage]]:
|
||
query_stmt = (
|
||
select(Message.messageId,Message.eventId ,Message.messageType, Message.eventType, Message.handle, Message.remark, Message.createTime,
|
||
Event.number,Event.name,
|
||
# Image.imageUrl, Image.localPath,
|
||
Temperature.temperature)
|
||
.select_from(Message)
|
||
.outerjoin(Event, Message.eventId == Event.eventId)
|
||
# .outerjoin(Image, Message.eventId == Image.eventId)
|
||
.outerjoin(Temperature, Message.eventId == Temperature.eventId)
|
||
.where(*condition)
|
||
.order_by(Message.createTime.desc())
|
||
.offset(skip)
|
||
.limit(limit)
|
||
)
|
||
|
||
messages = await db.execute(query_stmt)
|
||
messages = messages.mappings().all()
|
||
|
||
back = list()
|
||
for message in messages:
|
||
# 获取图片URL列表
|
||
query_image_stmt = (
|
||
select(Image.imageUrl)
|
||
.where(Image.eventId == message.get("eventId"))
|
||
)
|
||
images = await db.execute(query_image_stmt)
|
||
images = images.mappings().all()
|
||
|
||
# 将RowMapping转换为字典
|
||
message_dict = dict(message)
|
||
# 将图片URL列表转换为普通列表
|
||
image_urls = [dict(img)["imageUrl"] for img in images]
|
||
message_dict["imageUrl"] = image_urls
|
||
|
||
ocrAlertMessage = OcrAlertMessage(**message_dict)
|
||
back.append(ocrAlertMessage)
|
||
|
||
return back
|
||
|
||
async def get_messages_front(
|
||
self,
|
||
db: AsyncSession,
|
||
skip:int,
|
||
limit:int,
|
||
condition: list = []
|
||
) -> Optional[List[OcrAlertMessage]]:
|
||
query_stmt = (
|
||
select(Message.messageId,Message.eventId ,Message.messageType, Message.eventType, Message.handle, Message.remark, Message.createTime,
|
||
Event.number,Event.name,
|
||
# Image.imageUrl, Image.localPath,
|
||
RobotInfo.flvPtz, RobotInfo.flvTherm, RobotInfo.flvThermLight,
|
||
Temperature.temperature)
|
||
.select_from(Message)
|
||
.outerjoin(Event, Message.eventId == Event.eventId)
|
||
# .outerjoin(Image, Message.eventId == Image.eventId)
|
||
.outerjoin(RobotInfo, RobotInfo.number == Event.number)
|
||
.outerjoin(Temperature, Message.eventId == Temperature.eventId)
|
||
.where(*condition)
|
||
.order_by(Message.createTime.desc())
|
||
.offset(skip)
|
||
.limit(limit)
|
||
)
|
||
|
||
messages = await db.execute(query_stmt)
|
||
messages = messages.mappings().all()
|
||
|
||
back = list()
|
||
for message in messages:
|
||
# 获取图片URL列表
|
||
query_image_stmt = (
|
||
select(Image.imageUrl)
|
||
.where(Image.eventId == message.get("eventId"))
|
||
)
|
||
images = await db.execute(query_image_stmt)
|
||
images = images.mappings().all()
|
||
|
||
# 将RowMapping转换为字典
|
||
message_dict = dict(message)
|
||
# 将图片URL列表转换为普通列表
|
||
image_urls = [dict(img)["imageUrl"] for img in images]
|
||
message_dict["imageUrl"] = image_urls
|
||
|
||
commonAlertMessage = CommonAlertMessage(**message_dict)
|
||
back.append(commonAlertMessage)
|
||
|
||
return back
|
||
async def get_all_alert_message(
|
||
self,
|
||
db: AsyncSession,
|
||
number: str,
|
||
offset: int,
|
||
limit: int
|
||
):
|
||
"""
|
||
获取机器人所有的告警
|
||
"""
|
||
query_stmt = (
|
||
select(Message.messageId, Message.handle, Message.remark, Message.eventId,Message.createTime,Event.number, Event.name, Event.etypeName)
|
||
.select_from(Message)
|
||
.outerjoin(Event, Message.eventId==Event.eventId)
|
||
.where(Event.number == number)
|
||
.order_by(Message.createTime.desc())
|
||
.offset(offset)
|
||
.limit(limit)
|
||
)
|
||
results = await db.execute(query_stmt)
|
||
results = results.mappings().all()
|
||
|
||
data = list()
|
||
for result in results:
|
||
t = AllMessageDto(**result)
|
||
|
||
query_image_stmt = (
|
||
select(Image.imageUrl)
|
||
.where(Image.eventId == result.eventId)
|
||
)
|
||
image_list = await db.execute(query_image_stmt)
|
||
image_list = image_list.scalars().all()
|
||
t.imageList = image_list
|
||
t.imagePreview = image_list[0]
|
||
|
||
data.append(t)
|
||
return data
|
||
|
||
|
||
|
||
async def handle_ocr_alerts(
|
||
self,
|
||
db:AsyncSession,
|
||
messageIdList: List[int]
|
||
):
|
||
"""处理OCR告警消息
|
||
|
||
Args:
|
||
db: 数据库会话
|
||
messageIdList: 要处理的messageId列表
|
||
|
||
Returns:
|
||
bool: 更新是否成功
|
||
"""
|
||
try:
|
||
# 获取所有需要更新的消息ID
|
||
# 构建更新语句
|
||
update_stmt = (
|
||
update(Message)
|
||
.where(Message.messageId.in_(messageIdList))
|
||
.values(
|
||
handle="1",
|
||
updateTime=datetime.now()
|
||
)
|
||
)
|
||
|
||
# 准备更新数据
|
||
|
||
# 执行更新
|
||
await db.execute(
|
||
update_stmt,
|
||
# update_data,
|
||
execution_options={"synchronize_session": False}
|
||
)
|
||
await db.commit()
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"更新OCR告警消息失败: {str(e)}")
|
||
await db.rollback()
|
||
return False
|
||
|
||
async def handle_ocr_alerts_get(
|
||
self,
|
||
db: AsyncSession,
|
||
number: Optional[str] = None
|
||
):
|
||
try:
|
||
|
||
if number and len(number) > 0:
|
||
update_stmt = (
|
||
update(Message)
|
||
.values(
|
||
handle="1",
|
||
updateTime=datetime.now()
|
||
)
|
||
.where(Message.eventId == Event.eventId) # JOIN 条件放在 where()
|
||
.where(Event.number == number) # 过滤条件
|
||
.where(Message.handle == "0") # 过滤条件
|
||
)
|
||
print(number, "number")
|
||
else:
|
||
update_stmt = (
|
||
update(Message)
|
||
.where(Message.handle == "0")
|
||
.values(
|
||
handle = "1",
|
||
updateTime=datetime.now()
|
||
)
|
||
)
|
||
|
||
# 执行更新
|
||
await db.execute(
|
||
update_stmt,
|
||
execution_options={"synchronize_session": False}
|
||
)
|
||
await db.commit()
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"更新告警消息失败: {str(e)}")
|
||
await db.rollback()
|
||
return False
|
||
async def handle_ocr_alert(
|
||
self,
|
||
db: AsyncSession,
|
||
ocrAlertMessageDto: OcrAlertMessageDto,
|
||
):
|
||
try:
|
||
if ocrAlertMessageDto.number and len(ocrAlertMessageDto.number) > 0:
|
||
update_stmt = (
|
||
update(Message)
|
||
.where(Message.eventId == Event.eventId)
|
||
.where(Event.number == ocrAlertMessageDto.number)
|
||
.where(Message.messageId == ocrAlertMessageDto.messageId)
|
||
.values(
|
||
handle = "1",
|
||
remark = ocrAlertMessageDto.remark,
|
||
updateTime=datetime.now()
|
||
)
|
||
)
|
||
else:
|
||
update_stmt = (
|
||
update(Message)
|
||
.where(Message.messageId == ocrAlertMessageDto.messageId)
|
||
.values(
|
||
handle = "1",
|
||
remark = ocrAlertMessageDto.remark,
|
||
updateTime=datetime.now()
|
||
)
|
||
)
|
||
await db.execute(update_stmt)
|
||
await db.commit()
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"处理单个消息失败: {e}")
|
||
await db.rollback()
|
||
return False
|
||
|
||
async def get_alert_detail(
|
||
self,
|
||
db: AsyncSession,
|
||
messageId: int
|
||
) ->Optional[OcrAlertMessage]:
|
||
try:
|
||
select_stmt = (
|
||
select(Message.messageId,Message.eventId ,Message.messageType, Message.eventType, Message.handle, Message.remark, Message.createTime,
|
||
Event.number,Event.name,
|
||
Image.imageUrl, Image.localPath,
|
||
Temperature.temperature)
|
||
.select_from(Message)
|
||
.outerjoin(Event, Message.eventId == Event.eventId)
|
||
.outerjoin(Image, Message.eventId == Image.eventId)
|
||
.outerjoin(Temperature, Message.eventId == Temperature.eventId)
|
||
.where(Message.messageId == messageId)
|
||
)
|
||
|
||
result = await db.execute(select_stmt)
|
||
message = result.mappings().first()
|
||
|
||
if message:
|
||
# 获取图片URL列表
|
||
query_image_stmt = (
|
||
select(Image.imageUrl)
|
||
.where(Image.eventId == message.get("eventId"))
|
||
)
|
||
images = await db.execute(query_image_stmt)
|
||
images = images.mappings().all()
|
||
|
||
# 将RowMapping转换为字典
|
||
message_dict = dict(message)
|
||
# 添加图片URL列表
|
||
message_dict["imageUrl"] = images
|
||
|
||
return OcrAlertMessage(**message_dict)
|
||
return None
|
||
|
||
except Exception as e:
|
||
print(f"获取告警详情失败: {e}")
|
||
return None
|
||
|
||
async def get_alert_count(
|
||
self,
|
||
db: AsyncSession,
|
||
handle: str,
|
||
number: Optional[str] = None
|
||
):
|
||
try:
|
||
query_stmt = (
|
||
select(func.count(Message.messageId))
|
||
.select_from(Message)
|
||
.outerjoin(Event, Message.eventId == Event.eventId)
|
||
.where(and_(Message.handle == handle, (Event.number==number) if number else True))
|
||
)
|
||
|
||
result = await db.execute(query_stmt)
|
||
return result.scalar()
|
||
except Exception as e:
|
||
print(f"{e}")
|
||
|
||
async def get_robot_count(
|
||
self,
|
||
db: AsyncSession,
|
||
*, # 关键字参数分隔符,代表后面的参数一定要用关键字指定
|
||
status: list
|
||
):
|
||
try:
|
||
query_stmt = (
|
||
select(func.count(Robot.robotId))
|
||
.where(*status)
|
||
)
|
||
result = await db.execute(query_stmt)
|
||
return result.scalar()
|
||
|
||
except Exception as e:
|
||
print(f"{e}")
|
||
async def get_etype_name_list(
|
||
self,
|
||
db: AsyncSession
|
||
):
|
||
query_stmt = (
|
||
select(Event.etypeName)
|
||
.group_by(Event.etypeName)
|
||
|
||
)
|
||
|
||
results = await db.execute(query_stmt)
|
||
return results.scalars().all()
|
||
async def get_robot_task(
|
||
self,
|
||
db: AsyncSession,
|
||
robotId: Optional[str] = None
|
||
):
|
||
try:
|
||
# print("robotId", robotId)
|
||
query_stmt = (
|
||
select(Task.robotId, Task.taskName, Task.times).where(Task.robotId == robotId)
|
||
)
|
||
results = await db.execute(query_stmt)
|
||
results = results.mappings().all()
|
||
|
||
data = list()
|
||
for result in results:
|
||
t = TaskListDto(**result)
|
||
|
||
t.status = "0"
|
||
times = t.times.split(",")
|
||
for time in times:
|
||
if self.is_current_time_in_interval(time):
|
||
t.status = "1"
|
||
break
|
||
data.append(t)
|
||
|
||
return data
|
||
|
||
except Exception as e:
|
||
print(f"{e}")
|
||
async def get_messages_st(
|
||
self,
|
||
db: AsyncSession,
|
||
day: int
|
||
):
|
||
try:
|
||
now = datetime.now(timezone.utc)
|
||
start_time = now - timedelta(days=day)
|
||
|
||
query_stmt = (
|
||
select(
|
||
Message.eventType,
|
||
func.count(Message.eventType).label("count"))
|
||
.where(and_(start_time<=Message.createTime, Message.createTime <= now))
|
||
.group_by(Message.eventType)
|
||
)
|
||
result = await db.execute(query_stmt)
|
||
return [
|
||
{"eventType": row.eventType, "count": row.count}
|
||
for row in result
|
||
]
|
||
except Exception as e:
|
||
print(f"{e}")
|
||
|
||
def is_current_time_in_interval(self, interval):
|
||
"""检查当前时间是否在指定的时间区间内"""
|
||
# 获取当前时间字符串(格式 HH:MM)
|
||
current = datetime.now().strftime('%H:%M')
|
||
|
||
# 拆分时间区间字符串
|
||
start, end = interval.split(' - ')
|
||
|
||
# 直接比较时间字符串(24小时制时间字符串可直接比较)
|
||
return start <= current <= end
|
||
|
||
# async def get_robot_list(
|
||
# self,
|
||
# db: AsyncSession,
|
||
# get_robot_dto: GetRobotDto
|
||
# ):
|
||
# # 前端登录
|
||
# d = kangda._login_front()
|
||
# duty_list = kangda._get_robot_group(d["tenantInfoId"], d["token"])
|
||
|
||
|
||
|
||
|
||
event = CRUDEvent(Event) |