209 lines
6.6 KiB
Python
209 lines
6.6 KiB
Python
from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Form, Query
|
|
from sqlalchemy.orm import Session
|
|
from typing import List, Optional, Dict, Any
|
|
import os
|
|
import uuid
|
|
from datetime import datetime
|
|
from core.database import get_db
|
|
|
|
router = APIRouter()
|
|
|
|
# 文件上传配置
|
|
UPLOAD_DIR = "uploads"
|
|
VIDEO_DIR = os.path.join(UPLOAD_DIR, "videos")
|
|
IMAGE_DIR = os.path.join(UPLOAD_DIR, "images")
|
|
|
|
# 确保上传目录存在
|
|
os.makedirs(VIDEO_DIR, exist_ok=True)
|
|
os.makedirs(IMAGE_DIR, exist_ok=True)
|
|
|
|
# 允许的文件类型
|
|
ALLOWED_VIDEO_TYPES = ["video/mp4", "video/avi", "video/mov", "video/wmv"]
|
|
ALLOWED_IMAGE_TYPES = ["image/jpeg", "image/png", "image/gif", "image/bmp"]
|
|
|
|
# 文件大小限制 (MB)
|
|
MAX_VIDEO_SIZE = 100 # 100MB
|
|
MAX_IMAGE_SIZE = 10 # 10MB
|
|
|
|
@router.post("/video", summary="上传视频文件")
|
|
async def upload_video(
|
|
file: UploadFile = File(...),
|
|
device_id: Optional[int] = Form(None),
|
|
description: Optional[str] = Form(""),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""上传视频文件"""
|
|
try:
|
|
# 检查文件类型
|
|
if file.content_type not in ALLOWED_VIDEO_TYPES:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"不支持的文件类型: {file.content_type}"
|
|
)
|
|
|
|
# 检查文件大小
|
|
file_size = 0
|
|
content = await file.read()
|
|
file_size = len(content)
|
|
|
|
if file_size > MAX_VIDEO_SIZE * 1024 * 1024:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"文件大小超过限制: {MAX_VIDEO_SIZE}MB"
|
|
)
|
|
|
|
# 生成唯一文件名
|
|
file_id = str(uuid.uuid4())
|
|
file_extension = os.path.splitext(file.filename)[1]
|
|
filename = f"{file_id}{file_extension}"
|
|
file_path = os.path.join(VIDEO_DIR, filename)
|
|
|
|
# 保存文件
|
|
with open(file_path, "wb") as f:
|
|
f.write(content)
|
|
|
|
# TODO: 获取视频时长
|
|
duration = 30.5 # 模拟时长
|
|
|
|
return {
|
|
"file_id": file_id,
|
|
"file_url": f"/uploads/videos/{filename}",
|
|
"file_size": file_size,
|
|
"duration": duration,
|
|
"device_id": device_id,
|
|
"description": description,
|
|
"uploaded_at": datetime.now().isoformat()
|
|
}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"上传视频失败: {str(e)}")
|
|
|
|
@router.post("/image", summary="上传图片文件")
|
|
async def upload_image(
|
|
file: UploadFile = File(...),
|
|
event_id: Optional[int] = Form(None),
|
|
description: Optional[str] = Form(""),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""上传图片文件"""
|
|
try:
|
|
# 检查文件类型
|
|
if file.content_type not in ALLOWED_IMAGE_TYPES:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"不支持的文件类型: {file.content_type}"
|
|
)
|
|
|
|
# 检查文件大小
|
|
file_size = 0
|
|
content = await file.read()
|
|
file_size = len(content)
|
|
|
|
if file_size > MAX_IMAGE_SIZE * 1024 * 1024:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"文件大小超过限制: {MAX_IMAGE_SIZE}MB"
|
|
)
|
|
|
|
# 生成唯一文件名
|
|
file_id = str(uuid.uuid4())
|
|
file_extension = os.path.splitext(file.filename)[1]
|
|
filename = f"{file_id}{file_extension}"
|
|
file_path = os.path.join(IMAGE_DIR, filename)
|
|
|
|
# 保存文件
|
|
with open(file_path, "wb") as f:
|
|
f.write(content)
|
|
|
|
return {
|
|
"file_id": file_id,
|
|
"file_url": f"/uploads/images/{filename}",
|
|
"file_size": file_size,
|
|
"event_id": event_id,
|
|
"description": description,
|
|
"uploaded_at": datetime.now().isoformat()
|
|
}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"上传图片失败: {str(e)}")
|
|
|
|
@router.get("/files", summary="获取文件列表")
|
|
async def get_files(
|
|
file_type: Optional[str] = Query(None, description="文件类型: video/image"),
|
|
page: int = Query(1, ge=1, description="页码"),
|
|
size: int = Query(20, ge=1, le=100, description="每页数量"),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""获取上传文件列表"""
|
|
try:
|
|
# TODO: 实现真实的文件列表查询
|
|
# 当前返回模拟数据
|
|
files = [
|
|
{
|
|
"file_id": "video_123",
|
|
"file_url": "/uploads/videos/video_123.mp4",
|
|
"file_size": 1024000,
|
|
"file_type": "video",
|
|
"duration": 30.5,
|
|
"uploaded_at": "2024-01-15T10:30:00Z"
|
|
},
|
|
{
|
|
"file_id": "image_456",
|
|
"file_url": "/uploads/images/image_456.jpg",
|
|
"file_size": 256000,
|
|
"file_type": "image",
|
|
"uploaded_at": "2024-01-15T10:30:00Z"
|
|
}
|
|
]
|
|
|
|
# 过滤文件类型
|
|
if file_type:
|
|
files = [f for f in files if f["file_type"] == file_type]
|
|
|
|
total = len(files)
|
|
start = (page - 1) * size
|
|
end = start + size
|
|
paginated_files = files[start:end]
|
|
|
|
return {
|
|
"files": paginated_files,
|
|
"total": total,
|
|
"page": page,
|
|
"size": size
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"获取文件列表失败: {str(e)}")
|
|
|
|
@router.delete("/files/{file_id}", summary="删除文件")
|
|
async def delete_file(
|
|
file_id: str,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""删除上传的文件"""
|
|
try:
|
|
# TODO: 实现真实的文件删除
|
|
# 当前返回模拟数据
|
|
return {
|
|
"file_id": file_id,
|
|
"message": "文件已删除"
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"删除文件失败: {str(e)}")
|
|
|
|
@router.get("/stats", summary="获取上传统计")
|
|
async def get_upload_stats(db: Session = Depends(get_db)):
|
|
"""获取文件上传统计"""
|
|
try:
|
|
# TODO: 实现真实的上传统计
|
|
# 当前返回模拟数据
|
|
return {
|
|
"total_files": 156,
|
|
"total_size": 1024000000, # 1GB
|
|
"video_count": 89,
|
|
"image_count": 67,
|
|
"today_uploads": 12
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"获取上传统计失败: {str(e)}") |