Files
sibuti/transport/backend/app/routers/vehicles.py
2025-12-18 21:13:49 +03:00

140 lines
4.6 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.
from datetime import datetime, timedelta
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy import select, desc
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import get_db
from app.models import Vehicle, Position
from app.schemas import VehicleCreate, VehicleUpdate, VehicleResponse, VehicleWithPosition
from app.schemas.vehicle import LastPosition
router = APIRouter()
def get_vehicle_status(last_position: Optional[Position], now: datetime) -> str:
if not last_position:
return "offline"
time_diff = now - last_position.timestamp
if time_diff > timedelta(minutes=5):
return "offline"
elif last_position.speed < 2:
return "stopped"
else:
return "moving"
@router.get("", response_model=list[VehicleWithPosition])
async def get_vehicles(db: AsyncSession = Depends(get_db)):
"""Получить список всех транспортных средств с последними позициями"""
result = await db.execute(select(Vehicle))
vehicles = result.scalars().all()
response = []
now = datetime.utcnow()
for vehicle in vehicles:
# Get last position
pos_result = await db.execute(
select(Position)
.where(Position.vehicle_id == vehicle.id)
.order_by(desc(Position.timestamp))
.limit(1)
)
last_pos = pos_result.scalar_one_or_none()
vehicle_data = VehicleWithPosition(
id=vehicle.id,
name=vehicle.name,
type=vehicle.type,
created_at=vehicle.created_at,
last_position=LastPosition(
lat=last_pos.lat,
lon=last_pos.lon,
speed=last_pos.speed,
heading=last_pos.heading,
timestamp=last_pos.timestamp
) if last_pos else None,
status=get_vehicle_status(last_pos, now)
)
response.append(vehicle_data)
return response
@router.get("/{vehicle_id}", response_model=VehicleWithPosition)
async def get_vehicle(vehicle_id: int, db: AsyncSession = Depends(get_db)):
"""Получить информацию о транспортном средстве"""
result = await db.execute(select(Vehicle).where(Vehicle.id == vehicle_id))
vehicle = result.scalar_one_or_none()
if not vehicle:
raise HTTPException(status_code=404, detail="Vehicle not found")
# Get last position
pos_result = await db.execute(
select(Position)
.where(Position.vehicle_id == vehicle.id)
.order_by(desc(Position.timestamp))
.limit(1)
)
last_pos = pos_result.scalar_one_or_none()
now = datetime.utcnow()
return VehicleWithPosition(
id=vehicle.id,
name=vehicle.name,
type=vehicle.type,
created_at=vehicle.created_at,
last_position=LastPosition(
lat=last_pos.lat,
lon=last_pos.lon,
speed=last_pos.speed,
heading=last_pos.heading,
timestamp=last_pos.timestamp
) if last_pos else None,
status=get_vehicle_status(last_pos, now)
)
@router.post("", response_model=VehicleResponse, status_code=201)
async def create_vehicle(vehicle: VehicleCreate, db: AsyncSession = Depends(get_db)):
"""Создать новое транспортное средство"""
db_vehicle = Vehicle(**vehicle.model_dump())
db.add(db_vehicle)
await db.commit()
await db.refresh(db_vehicle)
return db_vehicle
@router.put("/{vehicle_id}", response_model=VehicleResponse)
async def update_vehicle(vehicle_id: int, vehicle: VehicleUpdate, db: AsyncSession = Depends(get_db)):
"""Обновить транспортное средство"""
result = await db.execute(select(Vehicle).where(Vehicle.id == vehicle_id))
db_vehicle = result.scalar_one_or_none()
if not db_vehicle:
raise HTTPException(status_code=404, detail="Vehicle not found")
update_data = vehicle.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(db_vehicle, field, value)
await db.commit()
await db.refresh(db_vehicle)
return db_vehicle
@router.delete("/{vehicle_id}", status_code=204)
async def delete_vehicle(vehicle_id: int, db: AsyncSession = Depends(get_db)):
"""Удалить транспортное средство"""
result = await db.execute(select(Vehicle).where(Vehicle.id == vehicle_id))
db_vehicle = result.scalar_one_or_none()
if not db_vehicle:
raise HTTPException(status_code=404, detail="Vehicle not found")
await db.delete(db_vehicle)
await db.commit()