Files
dashboard/backend/routes/ota.py
T
yangy 661b85ce62 Enhance backend functionality and frontend UI
- Updated main.py to include authentication for brand, model, and OTA routers.
- Added new OTA schemas in schemas.py for version management.
- Enhanced model retrieval with sorting options in models.py.
- Improved model update functionality to support multipart/form-data uploads.
- Updated frontend layout and styles for a more modern look, including new font integration.
- Implemented login route and authentication checks in router/index.js.
- Added sorting capabilities in model table and improved file handling in model view.
- Updated requirements.txt to include PyJWT for token management.
2026-05-14 17:54:36 +08:00

196 lines
8.0 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, Query, Body
from sqlalchemy.orm import Session
from typing import List, Optional
import logging
from database import get_db
from models.ota import Ota
from schemas import OtaCreate, OtaUpdate, OtaResponse
from response import ApiResponse, PageData
# Configure logging
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/ota", tags=["ota"])
@router.get("/", response_model=ApiResponse)
def get_ota_list(
skip: int = Query(0, ge=0, description="跳过记录数"),
limit: int = Query(100, ge=1, le=1000, description="返回记录数"),
verCode: Optional[int] = Query(None, description="按版本号查询"),
verName: Optional[str] = Query(None, description="按版本名称模糊查询"),
model: Optional[str] = Query(None, description="按设备型号模糊查询"),
status: Optional[int] = Query(None, ge=0, le=1, description="按状态查询"),
db: Session = Depends(get_db)
):
"""获取 OTA 版本列表(支持多种筛选条件)"""
try:
logger.info(f"Getting OTA list: skip={skip}, limit={limit}, verCode={verCode}, verName={verName}, model={model}, status={status}")
query = db.query(Ota)
# 应用筛选条件
if verCode is not None:
query = query.filter(Ota.verCode == verCode)
if verName:
query = query.filter(Ota.verName.like(f"%{verName}%"))
if model:
query = query.filter(Ota.model.like(f"%{model}%"))
if status is not None:
query = query.filter(Ota.status == status)
total = query.count()
query = query.order_by(Ota.verCode.desc())
ota_list = query.offset(skip).limit(limit).all()
logger.info(f"Found {len(ota_list)} OTA records, total={total}")
if not ota_list:
logger.warning("No OTA records found")
return ApiResponse(code=2, msg="empty", data=None)
# 转换为字典列表
ota_data = [ota.to_dict() for ota in ota_list]
return ApiResponse(code=1, msg="success", data={"items": ota_data, "total": total, "skip": skip, "limit": limit})
except Exception as e:
logger.error(f"Error getting OTA list: {str(e)}", exc_info=True)
return ApiResponse(code=0, msg="error", data=None)
@router.get("/{ota_id}", response_model=ApiResponse)
def get_ota(ota_id: int, db: Session = Depends(get_db)):
"""获取单个 OTA 版本"""
try:
logger.info(f"Getting OTA: id={ota_id}")
ota = db.query(Ota).filter(Ota.id == ota_id).first()
if not ota:
logger.warning(f"OTA not found: id={ota_id}")
return ApiResponse(code=2, msg="empty", data=None)
logger.info(f"OTA found: {ota.to_dict()}")
return ApiResponse(code=1, msg="success", data=ota.to_dict())
except Exception as e:
logger.error(f"Error getting OTA {ota_id}: {str(e)}", exc_info=True)
return ApiResponse(code=0, msg="error", data=None)
@router.post("/", response_model=ApiResponse)
def create_ota(ota: OtaCreate, db: Session = Depends(get_db)):
"""创建新 OTA 版本"""
try:
logger.info(f"Creating OTA: verCode={ota.verCode}, verName={ota.verName}, model={ota.model}")
# 检查版本号是否已存在
existing = db.query(Ota).filter(
Ota.verCode == ota.verCode,
Ota.model == ota.model
).first()
if existing:
logger.warning(f"OTA version already exists: verCode={ota.verCode}, model={ota.model}")
return ApiResponse(code=0, msg="该版本已存在", data=None)
db_ota = Ota(**ota.model_dump())
db.add(db_ota)
db.commit()
db.refresh(db_ota)
logger.info(f"OTA created successfully: id={db_ota.id}, verCode={db_ota.verCode}")
return ApiResponse(code=1, msg="success", data=db_ota.to_dict())
except Exception as e:
logger.error(f"Error creating OTA: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse(code=0, msg="error", data=None)
@router.put("/{ota_id}", response_model=ApiResponse)
def update_ota(ota_id: int, ota: OtaUpdate, db: Session = Depends(get_db)):
"""更新 OTA 版本"""
try:
logger.info(f"Updating OTA: id={ota_id}, data={ota.model_dump()}")
db_ota = db.query(Ota).filter(Ota.id == ota_id).first()
if not db_ota:
logger.warning(f"OTA not found: id={ota_id}")
return ApiResponse(code=2, msg="empty", data=None)
# 如果更新版本号,检查是否冲突
if ota.verCode or ota.model:
new_verCode = ota.verCode if ota.verCode is not None else db_ota.verCode
new_model = ota.model if ota.model is not None else db_ota.model
if new_verCode != db_ota.verCode or new_model != db_ota.model:
existing = db.query(Ota).filter(
Ota.verCode == new_verCode,
Ota.model == new_model
).first()
if existing:
logger.warning(f"OTA version already exists: verCode={new_verCode}, model={new_model}")
return ApiResponse(code=0, msg="该版本已存在", data=None)
# 更新字段
update_data = ota.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(db_ota, field, value)
db.commit()
db.refresh(db_ota)
logger.info(f"OTA updated successfully: id={db_ota.id}")
return ApiResponse(code=1, msg="success", data=db_ota.to_dict())
except Exception as e:
logger.error(f"Error updating OTA {ota_id}: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse(code=0, msg="error", data=None)
@router.delete("/{ota_id}", response_model=ApiResponse)
def delete_ota(ota_id: int, db: Session = Depends(get_db)):
"""删除 OTA 版本"""
try:
logger.info(f"Deleting OTA: id={ota_id}")
db_ota = db.query(Ota).filter(Ota.id == ota_id).first()
if not db_ota:
logger.warning(f"OTA not found: id={ota_id}")
return ApiResponse(code=2, msg="empty", data=None)
db.delete(db_ota)
db.commit()
logger.info(f"OTA deleted successfully: id={ota_id}")
return ApiResponse(code=1, msg="success", data=None)
except Exception as e:
logger.error(f"Error deleting OTA {ota_id}: {str(e)}", exc_info=True)
db.rollback()
return ApiResponse(code=0, msg="error", data=None)
@router.get("/latest/check", response_model=ApiResponse)
def check_latest_ta(
currentVerCode: int = Query(..., description="当前版本号"),
model: str = Query(..., description="设备型号"),
hw: Optional[int] = Query(None, description="硬件版本号"),
db: Session = Depends(get_db)
):
"""检查是否有可用的 OTA 升级"""
try:
logger.info(f"Checking latest OTA: currentVerCode={currentVerCode}, model={model}, hw={hw}")
# 构建查询条件
query = db.query(Ota).filter(
Ota.status == 1,
Ota.verCode > currentVerCode,
Ota.model == model
)
# 如果提供了硬件版本号,添加筛选条件
if hw is not None:
query = query.filter(Ota.hw == hw)
# 按版本号降序排列,获取最新版本
latest_ota = query.order_by(Ota.verCode.desc()).first()
if not latest_ota:
logger.info(f"No available OTA found for model={model}, currentVerCode={currentVerCode}")
return ApiResponse(code=2, msg="empty", data=None)
logger.info(f"Latest OTA found: verCode={latest_ota.verCode}, verName={latest_ota.verName}")
return ApiResponse(code=1, msg="success", data=latest_ota.to_dict())
except Exception as e:
logger.error(f"Error checking latest OTA: {str(e)}", exc_info=True)
return ApiResponse(code=0, msg="error", data=None)