from datetime import datetime, timedelta from pathlib import Path import os import shutil from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from sqlalchemy import func from redis import Redis from app.core.db import get_db from app.core.redis import get_redis from app.schemas.dashboard import DashboardSummary, UserStats, StorageStats, ServerStats from app.models import User router = APIRouter(prefix="/dashboard", tags=["dashboard"]) AUDIO_EXTENSIONS = {".mp3", ".wav", ".m4a", ".flac", ".aac", ".ogg"} def _get_base_dir() -> Path: return Path(__file__).resolve().parents[5] def _scan_storage(storage_dir: Path) -> tuple[int, int]: total_bytes = 0 file_count = 0 if not storage_dir.exists(): return 0, 0 for root, _dirs, files in os.walk(storage_dir): for name in files: file_path = Path(root) / name try: total_bytes += file_path.stat().st_size except OSError: continue file_count += 1 return total_bytes, file_count def _get_cpu_memory() -> tuple[float, float]: try: import psutil # type: ignore cpu = psutil.cpu_percent(interval=0.2) mem = psutil.virtual_memory().percent return float(cpu), float(mem) except Exception: return 0.0, 0.0 def _get_disk_usage(path: Path) -> float: try: total, used, _free = shutil.disk_usage(path) if total == 0: return 0.0 return round(used / total * 100, 2) except Exception: return 0.0 @router.get("/summary", response_model=DashboardSummary) def get_dashboard_summary(db: Session = Depends(get_db), redis: Redis = Depends(get_redis)): total_users = db.query(User).filter(User.is_deleted == 0).count() # 2. 今日新增 today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) new_today = db.query(User).filter( User.created_at >= today_start, User.is_deleted == 0 ).count() try: online = len(redis.keys("auth:online:*")) except Exception: online = 0 base_dir = _get_base_dir() storage_dir = base_dir / "storage" total_bytes, audio_files = _scan_storage(storage_dir) total_gb = round(total_bytes / (1024 ** 3), 2) cpu, mem = _get_cpu_memory() disk = _get_disk_usage(storage_dir if storage_dir.exists() else base_dir) return DashboardSummary( users=UserStats(total=total_users, new_today=new_today, online=online), storage=StorageStats(total_gb=total_gb, audio_files=audio_files), server=ServerStats(cpu=cpu, memory=mem, disk=disk), )